diff --git a/.github/workflows/build_cache.yaml b/.github/workflows/build_cache.yaml new file mode 100644 index 000000000..33b75ed70 --- /dev/null +++ b/.github/workflows/build_cache.yaml @@ -0,0 +1,48 @@ +name: Create and publish a cache Docker image +on: + push: + branches: + - main + paths: + - '**pom.xml' + - '**package.json' + tags-ignore: + - "*" + workflow_dispatch: +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} +jobs: + build-and-push-image: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: 'true' + - name: Log in to the Container registry + uses: docker/login-action@v3.0.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5.5.1 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=cache + flavor: | + latest=false + - name: Build and push Docker image + uses: docker/build-push-action@v5.1.0 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + file: Dockerfile-cache \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 000000000..06e443fec --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,40 @@ +name: Create and publish a Docker image +on: + release: + types: [published] + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} +jobs: + build-and-push-image: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: 'true' + - name: Log in to the Container registry + uses: docker/login-action@v3.0.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5.5.1 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + - name: Build and push Docker image + uses: docker/build-push-action@v5.1.0 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + "VER=${{ github.event.release.name }}" \ No newline at end of file diff --git a/.prettierrc.yml b/.prettierrc.yml index e6a0949ec..782c7c6d0 100644 --- a/.prettierrc.yml +++ b/.prettierrc.yml @@ -1,4 +1,6 @@ # Prettier configuration +plugins: + - prettier-plugin-java overrides: - files: - "*.java" diff --git a/Dockerfile b/Dockerfile index eb8d73581..5e9e91eab 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,36 +1,56 @@ -# syntax=docker/dockerfile:experimental +ARG CACHE=ghcr.io/scc-digitalhub/aac:cache +FROM ${CACHE} AS cache -FROM maven:3-openjdk-17 as build +FROM maven:3-openjdk-17 AS build +ARG VER=SNAPSHOT COPY ./src /tmp/src COPY ./pom.xml /tmp/pom.xml COPY ./user-console /tmp/user-console +COPY ./dev-console /tmp/dev-console +COPY ./admin-console /tmp/admin-console WORKDIR /tmp -RUN --mount=type=cache,target=/root/.m2,source=/root/.m2,from=smartcommunitylab/aac:cache \ - --mount=type=cache,target=/tmp/user-console/node_modules,source=/root/node_modules,from=smartcommunitylab/aac:cache \ - mvn package +RUN --mount=type=cache,target=/root/.m2,source=/cache/.m2,from=cache \ + --mount=type=cache,target=/tmp/target/node,source=/cache/target/node,from=cache \ + --mount=type=cache,target=/tmp/user-console/node_modules,source=/cache/user-console/node_modules,from=cache \ + --mount=type=cache,target=/tmp/dev-console/node_modules,source=/cache/dev-console/node_modules,from=cache \ + --mount=type=cache,target=/tmp/admin-console/node_modules,source=/cache/admin-console/node_modules,from=cache \ + mvn -Drevision=${VER} package -FROM eclipse-temurin:17-jdk-alpine as builder +FROM eclipse-temurin:17-jdk-alpine AS builder +WORKDIR /tmp COPY --from=build /tmp/target/aac.jar aac.jar RUN java -Djarmode=layertools -jar aac.jar extract -FROM eclipse-temurin:17-jdk-alpine -ARG USER=aac -ARG USER_ID=805 -ARG USER_GROUP=aac -ARG USER_GROUP_ID=805 -ARG USER_HOME=/home/${USER} -ENV FOLDER=/tmp/target +# FROM eclipse-temurin:17-jdk-alpine +# ARG USER=aac +# ARG USER_ID=805 +# ARG USER_GROUP=aac +# ARG USER_GROUP_ID=805 +# ARG USER_HOME=/home/${USER} +# ENV FOLDER=/tmp/target +# ENV APP=aac.jar +# # create a user group and a user +# RUN addgroup -g ${USER_GROUP_ID} ${USER_GROUP}; \ +# adduser -u ${USER_ID} -D -g '' -h ${USER_HOME} -G ${USER_GROUP} ${USER} ; + +# WORKDIR ${USER_HOME} +# COPY --chown=aac:aac --from=builder dependencies/ ${USER_HOME} +# COPY --chown=aac:aac --from=builder snapshot-dependencies/ ${USER_HOME} +# COPY --chown=aac:aac --from=builder spring-boot-loader/ ${USER_HOME} +# COPY --chown=aac:aac --from=builder application/ ${USER_HOME} +# USER 805 +# ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"] + +FROM gcr.io/distroless/java17-debian12:nonroot ENV APP=aac.jar -# create a user group and a user -RUN addgroup -g ${USER_GROUP_ID} ${USER_GROUP}; \ - adduser -u ${USER_ID} -D -g '' -h ${USER_HOME} -G ${USER_GROUP} ${USER} ; - -WORKDIR ${USER_HOME} -COPY --chown=aac:aac --from=builder dependencies/ ${USER_HOME} -COPY --chown=aac:aac --from=builder snapshot-dependencies/ ${USER_HOME} -COPY --chown=aac:aac --from=builder spring-boot-loader/ ${USER_HOME} -COPY --chown=aac:aac --from=builder application/ ${USER_HOME} -USER aac +WORKDIR /aac +LABEL org.opencontainers.image.source=https://github.com/scc-digitalhub/AAC +COPY --from=builder /tmp/dependencies/ ./ +COPY --from=builder /tmp/snapshot-dependencies/ ./ +COPY --from=builder /tmp/spring-boot-loader/ ./ +COPY --from=builder /tmp/application/ ./ +EXPOSE 8080 ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"] + diff --git a/Dockerfile-cache b/Dockerfile-cache index 60860269a..e316f553a 100644 --- a/Dockerfile-cache +++ b/Dockerfile-cache @@ -1,10 +1,24 @@ -FROM maven:3-openjdk-17 as mvn -COPY ./src /tmp/src -COPY ./user-console /tmp/user-console -COPY ./pom.xml /tmp/pom.xml -WORKDIR /tmp -RUN mvn install -DskipTests +FROM maven:3-openjdk-17 AS cache +RUN mkdir -p /build/src /build/user-console /build/dev-console /build/admin-console +COPY ./pom.xml /build/pom.xml +COPY ./user-console/package.json /build/user-console +COPY ./user-console/yarn.lock /build/user-console +COPY ./dev-console/package.json /build/dev-console +COPY ./dev-console/yarn.lock /build/dev-console +COPY ./admin-console/package.json /build/admin-console +COPY ./admin-console/yarn.lock /build/admin-console + +WORKDIR /build +RUN mvn dependency:go-offline +RUN mvn clean generate-resources FROM scratch -COPY --from=mvn /root/.m2 /root/.m2 -COPY --from=mvn /tmp/user-console/node_modules /root/node_modules +LABEL org.opencontainers.image.source=https://github.com/scc-digitalhub/digitalhub-core +WORKDIR /cache +COPY --from=cache /root/.m2 /cache/.m2 +COPY --from=cache /build/target /cache/target +COPY --from=cache /build/user-console/node_modules /cache/user-console/node_modules +COPY --from=cache /build/dev-console/node_modules /cache/dev-console/node_modules +COPY --from=cache /build/admin-console/node_modules /cache/admin-console/node_modules + + diff --git a/admin-console/.env b/admin-console/.env new file mode 100644 index 000000000..26019fc9d --- /dev/null +++ b/admin-console/.env @@ -0,0 +1,4 @@ +REACT_APP_API_URL= +REACT_APP_USER_CONSOLE=/console/user +REACT_APP_DEVELOPER_CONSOLE=/console/dev +REACT_APP_ADMIN_CONSOLE=/console/admin diff --git a/admin-console/.env.development b/admin-console/.env.development new file mode 100644 index 000000000..b07bd15a8 --- /dev/null +++ b/admin-console/.env.development @@ -0,0 +1,4 @@ +REACT_APP_API_URL=http://localhost:8080 +REACT_APP_USER_CONSOLE=http://localhost:8080/console/user +REACT_APP_DEVELOPER_CONSOLE=http://localhost:8080/console/dev +REACT_APP_ADMIN_CONSOLE=http://localhost:8080/console/admin \ No newline at end of file diff --git a/admin-console/.eslintrc b/admin-console/.eslintrc new file mode 100644 index 000000000..60b942039 --- /dev/null +++ b/admin-console/.eslintrc @@ -0,0 +1,31 @@ +{ + "parser": "@typescript-eslint/parser", + "extends": ["react-app", "plugin:prettier/recommended"], + "plugins": [ + "@typescript-eslint", + "import", + "jsx-a11y", + "prettier", + "react", + "react-hooks" + ], + "rules": { + "no-use-before-define": "off", + "prettier/prettier": "error", + "no-restricted-imports": [ + "error", + { + "paths": [ + { + "name": "@mui/material", + "importNames": ["makeStyles", "createMuiTheme"], + "message": "Please import from @mui/material/styles instead. See https://material-ui.com/guides/minimizing-bundle-size/#option-2 for more information" + } + ] + } + ], + "no-redeclare": "off", + "import/no-anonymous-default-export": "off", + "@typescript-eslint/no-redeclare": ["error"] + } +} diff --git a/admin-console/.gitignore b/admin-console/.gitignore new file mode 100644 index 000000000..4d29575de --- /dev/null +++ b/admin-console/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/admin-console/.prettierrc.js b/admin-console/.prettierrc.js new file mode 100644 index 000000000..d2ba7f89f --- /dev/null +++ b/admin-console/.prettierrc.js @@ -0,0 +1,15 @@ +module.exports = { + arrowParens: 'avoid', + bracketSpacing: true, + jsxBracketSameLine: false, + jsxSingleQuote: false, + printWidth: 80, + quoteProps: 'as-needed', + rangeStart: 0, + rangeEnd: Infinity, + semi: true, + singleQuote: true, + tabWidth: 4, + trailingComma: 'es5', + useTabs: false +} diff --git a/admin-console/.vscode/launch.json b/admin-console/.vscode/launch.json new file mode 100644 index 000000000..f6b35a0b6 --- /dev/null +++ b/admin-console/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "request": "launch", + "name": "Launch Chrome against localhost", + "url": "http://localhost:3000", + "webRoot": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/admin-console/README.md b/admin-console/README.md new file mode 100644 index 000000000..b58e0af83 --- /dev/null +++ b/admin-console/README.md @@ -0,0 +1,46 @@ +# Getting Started with Create React App + +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `yarn start` + +Runs the app in the development mode.\ +Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.\ +You will also see any lint errors in the console. + +### `yarn test` + +Launches the test runner in the interactive watch mode.\ +See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `yarn build` + +Builds the app for production to the `build` folder.\ +It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.\ +Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `yarn eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). diff --git a/admin-console/package.json b/admin-console/package.json new file mode 100644 index 000000000..d5df55eb3 --- /dev/null +++ b/admin-console/package.json @@ -0,0 +1,66 @@ +{ + "name": "admin-console", + "version": "1.0.0", + "private": true, + "license": "Apache-2.0", + "homepage": "/console/admin", + "dependencies": { + "@mui/icons-material": "^5.11.0", + "@mui/material": "^5.11.7", + "@testing-library/jest-dom": "^5.14.1", + "@testing-library/react": "^13.0.0", + "@testing-library/user-event": "^13.2.1", + "@types/jest": "^27.0.1", + "@types/node": "^16.7.13", + "@types/react": "^18.0.27", + "@types/react-dom": "^18.0.10", + "querystring": "^0.2.1", + "ra-data-json-server": "^4.7.2", + "react": "^18.2.0", + "react-admin": "^4.7.2", + "react-dom": "^18.2.0", + "react-scripts": "5.0.1", + "typeface-roboto-mono": "^1.1.13", + "typeface-titillium-web": "^1.1.13", + "typescript": "^4.4.2", + "web-vitals": "^2.1.0" + }, + "scripts": { + "start": "react-scripts start", + "start:dev": "env-cmd -f .env.development react-scripts start", + "start:local": "env-cmd -f .env.local react-scripts start", + "build": "env-cmd -f .env react-scripts build", + "dist": "env-cmd -f .env react-scripts build && gzipper c --gzip --brotli --remove-larger --skip-compressed ./build", + "lint": "eslint --ext .js,.ts,.tsx \"./src/**/*.{js,ts,tsx}\" ", + "prettier": "prettier --config ./.prettierrc.js --write --list-different \"src/**/*.{js,ts,tsx,css}\"", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "eslint": "^8.33.0", + "eslint-config-prettier": "^8.6.0", + "eslint-config-react-app": "^7.0.1", + "eslint-plugin-prettier": "^4.2.1", + "env-cmd": "^10.1.0", + "gzipper": "^7.2.0", + "prettier": "^2.8.3" + } +} diff --git a/admin-console/public/favicon.ico b/admin-console/public/favicon.ico new file mode 100644 index 000000000..801e2577b Binary files /dev/null and b/admin-console/public/favicon.ico differ diff --git a/admin-console/public/index.html b/admin-console/public/index.html new file mode 100644 index 000000000..17db8e675 --- /dev/null +++ b/admin-console/public/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + AAC user console + + + +
+ + + diff --git a/admin-console/public/manifest.json b/admin-console/public/manifest.json new file mode 100644 index 000000000..080d6c77a --- /dev/null +++ b/admin-console/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/admin-console/public/robots.txt b/admin-console/public/robots.txt new file mode 100644 index 000000000..e9e57dc4d --- /dev/null +++ b/admin-console/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/admin-console/src/App.css b/admin-console/src/App.css new file mode 100644 index 000000000..78b8850cf --- /dev/null +++ b/admin-console/src/App.css @@ -0,0 +1,38 @@ +.App { + text-align: center; +} + +.App-logo { + height: 40vmin; + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + .App-logo { + animation: App-logo-spin infinite 20s linear; + } +} + +.App-header { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; +} + +.App-link { + color: #61dafb; +} + +@keyframes App-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/admin-console/src/App.tsx b/admin-console/src/App.tsx new file mode 100644 index 000000000..4480b833c --- /dev/null +++ b/admin-console/src/App.tsx @@ -0,0 +1,126 @@ +import './App.css'; +import { + Admin, + CustomRoutes, + defaultTheme, + EditGuesser, + ListGuesser, + Resource, +} from 'react-admin'; +import { Route } from 'react-router-dom'; +import appDataProvider from './dataProvider'; +import appAuthProvider from './authProvider'; +import i18nProvider from './i18nProvider'; +import MyLayout from './components/layout'; + +import 'typeface-titillium-web'; +import 'typeface-roboto-mono'; + +import GroupIcon from '@mui/icons-material/Group'; +import AccountBoxIcon from '@mui/icons-material/AccountBox'; +import VpnKeyIcon from '@mui/icons-material/VpnKey'; +import ShowChartIcon from '@mui/icons-material/ShowChart'; +import WorkspacesIcon from '@mui/icons-material/Workspaces'; + +import AdminDashboard from './pages/dashboard'; +import { RealmsPage } from './pages/realms'; + +import { LoginPage } from './pages/login'; +import { RealmCreate, RealmEdit } from './resources/realms'; +import { MetricsList } from './resources/metrics'; + +const API_URL: string = process.env.REACT_APP_API_URL as string; +const dataProvider = appDataProvider(API_URL); +const authProvider = appAuthProvider(API_URL); + +const myTheme = { + ...defaultTheme, + palette: { + primary: { + main: '#0066cc', + dark: '#00478e', + light: '#3384d6', + }, + secondary: { + main: '#b2b2b2', + dark: '#7c7c7c', + light: '#c1c1c1', + }, + }, + typography: { + fontFamily: ['"Titillium Web"', 'Geneva', 'Tahoma', 'sans-serif'].join( + ',' + ), + h1: { + fontWeight: 700, + }, + h2: { + fontWeight: 700, + }, + h3: { + fontWeight: 700, + }, + h4: { + fontWeight: 700, + }, + h5: { + fontWeight: 700, + }, + button: { + fontFamily: [ + '"Titillium Web"', + 'Geneva', + 'Tahoma', + 'sans-serif', + ].join(','), + fontWeight: 600, + textTransform: 'none' as const, + fontSize: '0.90rem', + }, + body1: { + // fontFamily: ['Lora', 'serif'].join(','), + }, + body2: { + // fontFamily: ['Lora', 'serif'].join(','), + }, + // Use the system font instead of the default Roboto font. + // fontFamily: ['-apple-system', 'BlinkMacSystemFont', '"Segoe UI"', 'Arial', 'sans-serif'].join(','), + }, + components: { + // Name of the component + MuiCardContent: { + styleOverrides: { + // Name of the slot + root: { + // fontFamily: 'Lora,serif' as const, + }, + }, + }, + }, +}; + +const App = () => ( + } + authCallbackPage={false} + requireAuth + disableTelemetry + > + + {/* */} + +); + +export default App; diff --git a/admin-console/src/authProvider.tsx b/admin-console/src/authProvider.tsx new file mode 100644 index 000000000..caca52894 --- /dev/null +++ b/admin-console/src/authProvider.tsx @@ -0,0 +1,84 @@ +import { AuthProvider, fetchUtils, Options } from 'react-admin'; + +const fetchJson = (url: string, options: Options = {}) => { + if (!options.headers) { + options.headers = new Headers({ Accept: 'application/json' }); + } + + options.credentials = 'include'; + + return fetchUtils.fetchJson(url, options); +}; + +export default (baseUrl: string, httpClient = fetchJson): AuthProvider => { + const apiUrl = baseUrl + '/console/user'; + + return { + login: async (params: any) => {}, + logout: async (params: any) => { + window.location.href = `${baseUrl}/logout`; + return; + }, + checkError: async (error: any) => { + const status = error.status; + if (status === 401 || status === 403) { + return Promise.reject(); + } + // other error code (404, 500, etc): no need to log out + return Promise.resolve(); + }, + checkAuth: async (params: any) => { + // const url = `${apiUrl}/status`; + // const { status } = await httpClient(url); + // if (status !== 200) { + // throw new Error('unauthorized'); + // } + //load from authorities + const url = `${apiUrl}/authorities`; + const { status, json } = await httpClient(url); + if (status !== 200 || !json) { + throw new Error('permissions error'); + } + + //require admin + const isAdmin = json.find((r: any) => r.authority === 'ROLE_ADMIN'); + if (!isAdmin) { + throw new Error('permissions error'); + } + }, + getIdentity: async () => { + //load from profile + let url = `${apiUrl}/me`; + const { status, json } = await httpClient(url); + + if (status !== 200 || !json || !json.subjectId) { + throw new Error('profile error'); + } + + //explode realm model + url = `${apiUrl}/realm`; + const { status: rstatus, json: rjson } = await httpClient(url); + + if (rstatus !== 200 || !rjson || !rjson.slug) { + throw new Error('profile error'); + } + + return { + id: json.subjectId, + fullName: json.username, + ...json, + realm: rjson, + }; + }, + getPermissions: async () => { + //load from authorities + const url = `${apiUrl}/authorities`; + const { status, json } = await httpClient(url); + if (status !== 200 || !json) { + throw new Error('permissions error'); + } + + return json; + }, + }; +}; diff --git a/admin-console/src/components/SelectButton.tsx b/admin-console/src/components/SelectButton.tsx new file mode 100644 index 000000000..ddeb12d38 --- /dev/null +++ b/admin-console/src/components/SelectButton.tsx @@ -0,0 +1,40 @@ +import { Link } from 'react-router-dom'; +import { useResourceContext, useCreatePath, useRecordContext } from 'ra-core'; +import { Button, ShowButtonProps } from 'react-admin'; +import VisibilityIcon from '@mui/icons-material/Visibility'; + +const defaultIcon = ; +const DEV_URL: string = process.env.REACT_APP_DEVELOPER_CONSOLE as string; + +export const SelectButton = (props: ShowButtonProps) => { + const { + className, + icon = defaultIcon, + label = 'ra.action.show', + resource: resourceProp, + variant, + ...rest + } = props; + + const resource = useResourceContext(props); + const record = useRecordContext(props); + + const path = DEV_URL + '/-/' + record.id; + const handleClick = () => { + window.location.href = path; + return; + }; + return ( + + ); +}; + +export default SelectButton; diff --git a/admin-console/src/components/cardToolbar.tsx b/admin-console/src/components/cardToolbar.tsx new file mode 100644 index 000000000..9596e0141 --- /dev/null +++ b/admin-console/src/components/cardToolbar.tsx @@ -0,0 +1,23 @@ +import { styled } from '@mui/material/styles'; +import { Toolbar } from '@mui/material'; +import { ToolbarProps } from 'react-admin'; + +export const CardToolbar = (props: ToolbarProps) => { + const { children, className, resource, ...rest } = props; + + return ( + + {children} + + ); +}; + +const StyledToolbar = styled(Toolbar, { + name: 'CardToolbar', +})(({ theme }) => ({ + flex: 1, + display: 'flex', + backgroundColor: theme.palette.grey[100], +})); + +export default CardToolbar; diff --git a/admin-console/src/components/createButton.tsx b/admin-console/src/components/createButton.tsx new file mode 100644 index 000000000..d7b478fab --- /dev/null +++ b/admin-console/src/components/createButton.tsx @@ -0,0 +1,37 @@ +import { Link } from 'react-router-dom'; +import { useResourceContext, useCreatePath } from 'ra-core'; +import { Button, CreateButtonProps } from 'react-admin'; +import ContentAdd from '@mui/icons-material/Add'; + +const defaultIcon = ; + +export const CreateButton = (props: CreateButtonProps) => { + const { + className, + icon = defaultIcon, + label = 'ra.action.create', + resource: resourceProp, + variant, + ...rest + } = props; + + const resource = useResourceContext(props); + const createPath = useCreatePath(); + + const path = createPath({ resource, type: 'create' }); + + return ( + + ); +}; + +export default CreateButton; diff --git a/admin-console/src/components/gridList.tsx b/admin-console/src/components/gridList.tsx new file mode 100644 index 000000000..16ec496c6 --- /dev/null +++ b/admin-console/src/components/gridList.tsx @@ -0,0 +1,138 @@ +import { Box, Grid } from '@mui/material'; +import { + useListContext, + RecordContextProvider, + SimpleListProps, + RaRecord, + useTranslate, + Identifier, +} from 'react-admin'; +import LinearProgress from '@mui/material/LinearProgress'; +import { Card, CardContent, CardActions, CardHeader } from '@mui/material'; +import { isValidElement, ReactElement, ReactNode } from 'react'; + +// const style = { +// // Use flex layout with column direction for components in the card +// // (CardContent and CardActions) +// display: 'flex', +// flexDirection: 'column', + +// // Justify the content so that CardContent will always be at the top of the card, +// // and CardActions will be at the bottom +// justifyContent: 'space-between', +// }; + +export const GridList = ( + props: GridListProps +) => { + const { cols = 6 } = props; + const { primaryText, secondaryText, tertiaryText, icon, actions } = props; + + const { data, isLoading } = useListContext(props); + // const resource = useResourceContext(props); + const translate = useTranslate(); + + if (isLoading === true) { + return ; + } + + if (!data) return null; + + return ( + + + {data.map((record, rowIndex) => ( + + + + {!!primaryText && + (isValidElement(primaryText) ? ( + primaryText + ) : ( + + ))} + + {secondaryText && + (typeof secondaryText === 'string' + ? translate(secondaryText, { + ...record, + _: secondaryText, + }) + : isValidElement(secondaryText) + ? secondaryText + : secondaryText(record, record.id))} + + {actions && ( + + {isValidElement(actions) + ? actions + : actions(record, record.id)} + + )} + + + + ))} + + + ); +}; + +export type FunctionToElement = ( + record: RecordType, + id: Identifier +) => ReactNode; + +export interface GridListProps + extends SimpleListProps { + cols?: number; + icon?: FunctionToElement | ReactElement; + tertiaryText?: FunctionToElement | string; + actions?: FunctionToElement | ReactElement; +} +export default GridList; diff --git a/admin-console/src/components/layout.tsx b/admin-console/src/components/layout.tsx new file mode 100644 index 000000000..ae827a9af --- /dev/null +++ b/admin-console/src/components/layout.tsx @@ -0,0 +1,133 @@ +import { + AppBar, + AppBarProps, + Layout, + LayoutProps, + MenuProps, + useGetIdentity, + useTranslate, +} from 'react-admin'; +import { Box, Typography } from '@mui/material'; +import { Menu } from 'react-admin'; +import { FunctionComponent } from 'react'; + +import LockIcon from '@mui/icons-material/Lock'; +import AccountBoxIcon from '@mui/icons-material/AccountBox'; +import VpnKeyIcon from '@mui/icons-material/VpnKey'; +import AppShortcutIcon from '@mui/icons-material/AppShortcut'; + +import { Logout, UserMenu } from 'react-admin'; +import MenuItem from '@mui/material/MenuItem'; +import { MenuItemProps } from '@mui/material/MenuItem'; + +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemText from '@mui/material/ListItemText'; +import DeveloperModeIcon from '@mui/icons-material/DeveloperMode'; +import GroupIcon from '@mui/icons-material/Group'; +import SettingsIcon from '@mui/icons-material/Settings'; + +import React from 'react'; + +const DEV_URL: string = process.env.REACT_APP_DEVELOPER_CONSOLE as string; +const ADMIN_URL: string = process.env.REACT_APP_ADMIN_CONSOLE as string; +const USER_URL: string = process.env.REACT_APP_USER_CONSOLE as string; + +const DevConsoleMenu: FunctionComponent> = React.forwardRef( + function MenuToDev(props, ref) { + const translate = useTranslate(); + const isXSmall = false; + const handleClick = () => { + window.location.href = DEV_URL; + return; + }; + return ( + + + + + {translate('developer')} + + ); + } +); + +const UserConsoleMenu: FunctionComponent> = + React.forwardRef(function MenuToUser(props, ref) { + const translate = useTranslate(); + const isXSmall = false; + const handleClick = () => { + window.location.href = USER_URL; + return; + }; + return ( + + + + + {translate('user')} + + ); + }); + +const MyUserMenu = () => { + const { data } = useGetIdentity(); + + const isDeveloper = + data && + data.authorities.find( + (r: any) => + r.role && + (r.role === 'ROLE_DEVELOPER' || r.role === 'ROLE_ADMIN') + ); + + return ( + + {isDeveloper && } + + + + ); +}; + +const MyAppBar = (props: AppBarProps) => { + const title = 'AAC'; + return ( + }> + + + {title} + + + + ); +}; + +const MyLayout = (props: LayoutProps) => ( + +); + +export default MyLayout; diff --git a/admin-console/src/components/pageTitle.tsx b/admin-console/src/components/pageTitle.tsx new file mode 100644 index 000000000..1fc821ac5 --- /dev/null +++ b/admin-console/src/components/pageTitle.tsx @@ -0,0 +1,34 @@ +import { Typography, Paper, Container } from '@mui/material'; +import { isValidElement, ReactElement } from 'react'; + +export const PageTitle = (props: PageTitleProps) => { + const { text, secondaryText, icon } = props; + + return ( + + + {icon && isValidElement(icon) ? icon : ''} + + {text} + + {secondaryText && ( + + {secondaryText} + + )} + + + ); +}; + +export interface PageTitleProps { + text: string; + secondaryText?: string; + icon?: ReactElement; +} diff --git a/admin-console/src/components/spacer.tsx b/admin-console/src/components/spacer.tsx new file mode 100644 index 000000000..9421218a1 --- /dev/null +++ b/admin-console/src/components/spacer.tsx @@ -0,0 +1,23 @@ +import { Divider, DividerProps } from '@mui/material'; + +export const Spacer = (props: SpacerProps) => { + const { space, sx, ...rest } = props; + const direction = + rest?.orientation === 'vertical' + ? 'borderRightWidth' + : 'borderBottomWidth'; + return ( + + ); +}; + +export interface SpacerProps extends DividerProps { + space?: string; +} diff --git a/admin-console/src/dataProvider.tsx b/admin-console/src/dataProvider.tsx new file mode 100644 index 000000000..d6400bea7 --- /dev/null +++ b/admin-console/src/dataProvider.tsx @@ -0,0 +1,108 @@ +import { stringify } from 'querystring'; +import { fetchUtils, DataProvider } from 'ra-core'; +import jsonServerProvider from 'ra-data-json-server'; +import { Options } from 'react-admin'; + +const fetchJson = (url: string, options: Options = {}) => { + if (!options.headers) { + options.headers = new Headers({ Accept: 'application/json' }); + } + + options.credentials = 'include'; + + return fetchUtils.fetchJson(url, options); +}; + +export default (baseUrl: string, httpClient = fetchJson): DataProvider => { + const apiUrl = baseUrl + '/console/admin'; + const provider = jsonServerProvider(apiUrl, httpClient); + + return { + apiUrl: async () => apiUrl, + invoke: ({ + path, + params, + body, + options, + }: { + path: string; + params?: any; + body?: string; + options?: Options; + }) => { + let url = `${apiUrl}/${path}`; + if (params) { + url = `${apiUrl}/${path}?${stringify(params)}`; + } + const opts = options ? options : {}; + if (body) { + opts.body = body; + } + return httpClient(url, opts).then(({ headers, json }) => { + return json; + }); + }, + appProps: () => { + const url = `${apiUrl}/props`; + return httpClient(url).then(({ json }) => { + return json; + }); + }, + getList: (resource, params) => { + const { page, perPage } = params.pagination; + const { field, order } = params.sort; + const query = { + ...fetchUtils.flattenObject(params.filter), + sort: field + ',' + order, + page: page - 1, + size: perPage, + }; + const url = `${apiUrl}/${resource}?${stringify(query)}`; + + return httpClient(url).then(({ headers, json }) => { + if (json && Array.isArray(json)) { + return { + data: json, + total: json.length, + }; + } + if (!json.content) { + throw new Error('the response must match page<> model'); + } + return { + data: json.content, + total: parseInt(json.totalElements, 10), + }; + }); + }, + getOne: (resource, params) => provider.getOne(resource, params), + getMany: (resource, params) => provider.getMany(resource, params), + getManyReference: (resource, params) => { + const { page, perPage } = params.pagination; + const { field, order } = params.sort; + const query = { + ...fetchUtils.flattenObject(params.filter), + [params.target]: params.id, + sort: field + ',' + order, + page: page - 1, + size: perPage, + }; + const url = `${apiUrl}/${resource}?${stringify(query)}`; + + return httpClient(url).then(({ headers, json }) => { + if (!json.content) { + throw new Error('the response must match page<> model'); + } + return { + data: json.content, + total: parseInt(json.totalElements, 10), + }; + }); + }, + update: (resource, params) => provider.update(resource, params), + updateMany: (resource, params) => provider.updateMany(resource, params), + create: (resource, params) => provider.create(resource, params), + delete: (resource, params) => provider.delete(resource, params), + deleteMany: (resource, params) => provider.deleteMany(resource, params), + }; +}; diff --git a/admin-console/src/i18n/en.tsx b/admin-console/src/i18n/en.tsx new file mode 100644 index 000000000..1450bc058 --- /dev/null +++ b/admin-console/src/i18n/en.tsx @@ -0,0 +1,88 @@ +import { TranslationMessages } from 'ra-core'; +import englishMessages from 'ra-language-english'; +import utils from '../utils'; + +const raMessages = utils.deepCopy(englishMessages); + +const enMessages: TranslationMessages = { + ...raMessages, + admin: 'Admin', + developer: 'Developer', + user: 'User', + security: 'Security', + realms: 'Realms', + + resources: { + realms: { + name: 'Realm |||| Realms', + fields: {}, + helperText: { + slug: 'A slug is the addressable identifier for the realm, used for URLs, redirects, etc. ', + name: 'The user-facing identifier for the realm', + public: 'When set, the realm will be listed on public pages', + }, + }, + }, + page: { + dashboard: { + welcome: 'Admin console', + description: + 'Manage the server and the global settings, along with realm registrations', + realms: { + title: 'Realms', + description: 'View and manage realms', + manage: 'Manage realms', + }, + appProps: { + title: 'Application properties', + description: 'Current properties from config', + }, + }, + realms: { + header: 'Realms', + description: 'View, manage and delete realms', + create: { + title: 'Add realm', + description: 'Create the registration for a new realm', + }, + edit: { + title: 'Edit realm', + description: 'Modify registration properties for realm', + }, + }, + login: { + header: 'Login', + description: 'Login is required to access the console', + }, + }, + alert: {}, + action: {}, + field: { + name: 'Name', + slug: 'Slug', + id: 'id', + email: 'Email', + url: 'URL', + logo: 'Logo', + lang: 'Language', + footer: 'Footer', + }, + error: { + already_registered: 'Already registered', + authentication_service: + 'Authentication problem. Please try again later', + bad_credentials: 'Invalid user or password', + duplicated_data: 'Duplicated data', + internal_error: 'Internal error. Please try again', + invalid_data: 'Invalid field data', + missing_data: 'Missing data', + invalid_field: 'Invalid field data', + unsupported_operation: 'Unsupported operation', + wrong_password: 'Wrong password', + unauthenticated_user: 'User must be authenticated', + invalid_slug: + 'Invalid slug: only alphanumeric characters (plus -) are allowed', + }, +}; + +export default enMessages; diff --git a/admin-console/src/i18nProvider.tsx b/admin-console/src/i18nProvider.tsx new file mode 100644 index 000000000..c57ad2566 --- /dev/null +++ b/admin-console/src/i18nProvider.tsx @@ -0,0 +1,15 @@ +import polyglotI18nProvider from 'ra-i18n-polyglot'; +import { TranslationMessages } from 'react-admin'; +import englishMessages from './i18n/en'; + +const messages: Record = { + en: englishMessages, +}; + +export default polyglotI18nProvider( + (locale: string) => { + return messages[locale]; + }, + 'en', + [{ locale: 'en', name: 'EN' }] +); diff --git a/admin-console/src/index.css b/admin-console/src/index.css new file mode 100644 index 000000000..4b326a5a4 --- /dev/null +++ b/admin-console/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', + 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', + 'Helvetica Neue', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/admin-console/src/index.tsx b/admin-console/src/index.tsx new file mode 100644 index 000000000..94773e4de --- /dev/null +++ b/admin-console/src/index.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import './index.css'; +import App from './App'; +import { Spacer } from './components/spacer'; + +const root = ReactDOM.createRoot( + document.getElementById('root') as HTMLElement +); +root.render( + + + + +); diff --git a/admin-console/src/logo.svg b/admin-console/src/logo.svg new file mode 100644 index 000000000..fd873b35a --- /dev/null +++ b/admin-console/src/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-console/src/pages/dashboard.tsx b/admin-console/src/pages/dashboard.tsx new file mode 100644 index 000000000..b6daee2eb --- /dev/null +++ b/admin-console/src/pages/dashboard.tsx @@ -0,0 +1,222 @@ +import * as React from 'react'; +import { Link } from 'react-router-dom'; +import { + useGetIdentity, + useTranslate, + useDataProvider, + useGetOne, +} from 'react-admin'; +import LinearProgress from '@mui/material/LinearProgress'; +import { + Card, + CardContent, + CardActions, + CardHeader, + Box, + Table, + TableBody, + TableCell, + TableContainer, + TableRow, +} from '@mui/material'; +import { Container, Grid, Button, Avatar } from '@mui/material'; + +import SettingsIcon from '@mui/icons-material/Settings'; +import WorkspacesIcon from '@mui/icons-material/Workspaces'; +import KeyIcon from '@mui/icons-material/Key'; +import AppShortcutIcon from '@mui/icons-material/AppShortcut'; +import DisplaySettingsIcon from '@mui/icons-material/DisplaySettings'; + +import { PageTitle } from '../components/pageTitle'; +import { useEffect, useState } from 'react'; + +const AppPropsCard = () => { + const translate = useTranslate(); + const dataProvider = useDataProvider(); + const [props, setProps] = useState(); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(); + + useEffect(() => { + dataProvider + .appProps() + .then(function (data: any) { + setProps(data); + setLoading(false); + }) + .catch(function (error: any) { + setError(error); + setLoading(false); + }); + }, []); + + return ( + + } + titleTypographyProps={{ variant: 'h6' }} + /> + + {translate('page.dashboard.appProps.description')} + {props && ( + + + + + {Object.entries(props).map( + (attr: any, key: any) => { + return ( + + + + {translate( + 'field.' + + attr[0] + )} + + + + {attr[1]} + + + ); + } + )} + +
+
+
+ )} +
+
+ ); +}; + +interface MetricProps { + id: string; + icon?: string; +} + +const MetricsCard = (props: MetricProps) => { + const { id, icon } = props; + const translate = useTranslate(); + const dataProvider = useDataProvider(); + const [metric, setMetric] = useState(); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(); + + useEffect(() => { + dataProvider + .getOne('metrics', { id: id }) + .then(function (data: any) { + setMetric(data.data); + setLoading(false); + }) + .catch(function (error: any) { + setError(error); + setLoading(false); + }); + }, []); + + return ( + + } + titleTypographyProps={{ variant: 'h6' }} + /> + + {metric && ( + +

{metric.description}

+

{metric.sample?.value}

+
+ )} +
+
+ ); +}; + +const metricValue = ({ + value, +}: // baseUnit, +{ + value: string; + // baseUnit: string; +}) => { + console.log(value); + return value; +}; + +const AdminDashboard = () => { + const { data, isLoading } = useGetIdentity(); + const translate = useTranslate(); + if (isLoading === true || !data) { + return ; + } + return ( + + + + + ) + } + /> + + + + + + + + + + + + + } + titleTypographyProps={{ variant: 'h6' }} + /> + + {translate('page.dashboard.realms.description')} + + + + + + + + + ); +}; + +export default AdminDashboard; diff --git a/admin-console/src/pages/login.tsx b/admin-console/src/pages/login.tsx new file mode 100644 index 000000000..d487075f9 --- /dev/null +++ b/admin-console/src/pages/login.tsx @@ -0,0 +1,34 @@ +import { useTranslate } from 'react-admin'; +import { Container, Avatar } from '@mui/material'; + +import { PageTitle } from '../components/pageTitle'; +import LoginIcon from '@mui/icons-material/Login'; + +export const LoginPage = () => { + const translate = useTranslate(); + + return ( + + + + + } + /> + + ); +}; diff --git a/admin-console/src/pages/realms.tsx b/admin-console/src/pages/realms.tsx new file mode 100644 index 000000000..46a79d698 --- /dev/null +++ b/admin-console/src/pages/realms.tsx @@ -0,0 +1,65 @@ +import { + useTranslate, + useGetIdentity, + Labeled, + TextField, + DeleteWithConfirmButton, + LinearProgress, +} from 'react-admin'; +import { + Box, + Grid, + Typography, + Card, + ListItem, + Avatar, + Alert, +} from '@mui/material'; +import GroupIcon from '@mui/icons-material/Group'; +import DeleteForeverIcon from '@mui/icons-material/DeleteForever'; +import PersonAddIcon from '@mui/icons-material/PersonAdd'; +import WarningIcon from '@mui/icons-material/Warning'; + +import { List as MuiList } from '@mui/material'; + +import { PageTitle } from '../components/pageTitle'; +import { CardToolbar } from '../components/cardToolbar'; +import CreateButton from '../components/createButton'; + +import { RealmsList } from '../resources/realms'; + +export const RealmsPage = () => { + const translate = useTranslate(); + const { isLoading, data } = useGetIdentity(); + + if (isLoading || !data) { + return ; + } + + return ( + + + + + } + /> + + + + ); +}; diff --git a/admin-console/src/react-app-env.d.ts b/admin-console/src/react-app-env.d.ts new file mode 100644 index 000000000..6431bc5fc --- /dev/null +++ b/admin-console/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/admin-console/src/resources/metrics.tsx b/admin-console/src/resources/metrics.tsx new file mode 100644 index 000000000..640f84f34 --- /dev/null +++ b/admin-console/src/resources/metrics.tsx @@ -0,0 +1,30 @@ +import { + ArrayField, + ChipField, + Datagrid, + List, + SingleFieldList, + TextField, +} from 'react-admin'; + +export const MetricsList = () => ( + + + + + + + {/* + + + + */} + + + + + + + + +); diff --git a/admin-console/src/resources/realms.tsx b/admin-console/src/resources/realms.tsx new file mode 100644 index 000000000..9011189da --- /dev/null +++ b/admin-console/src/resources/realms.tsx @@ -0,0 +1,136 @@ +import { + Edit, + EditButton, + useEditContext, + DateField, + Labeled, + TextField, + Toolbar, + DeleteWithConfirmButton, + LinearProgress, + ListButton, + SaveButton, + useTranslate, + Datagrid, + BooleanField, + BooleanInput, + Button, + CreateButton, + ExportButton, + FilterButton, + FilterForm, + TopToolbar, + Create, + regex, +} from 'react-admin'; +import { List, SimpleForm, TextInput } from 'react-admin'; +import { Box, ListItem, Stack, Typography } from '@mui/material'; +import PersonIcon from '@mui/icons-material/Person'; +import KeyIcon from '@mui/icons-material/Key'; +import SwitchAccountIcon from '@mui/icons-material/SwitchAccount'; +import GoogleIcon from '@mui/icons-material/Google'; +import FacebookIcon from '@mui/icons-material/Facebook'; +import AppleIcon from '@mui/icons-material/Apple'; +import AlertError from '@mui/icons-material/ErrorOutline'; +import { Toolbar as MuiToolbar } from '@mui/material'; + +import { List as MuiList } from '@mui/material'; + +import GridList from '../components/gridList'; +import { CardToolbar } from '../components/cardToolbar'; +import SelectButton from '../components/SelectButton'; + +const ListActions = () => ( + + + +); + +export const RealmsList = () => { + const filters = []; + + return ( + } filters={filters}> + + + + + + + + + + + + ); +}; + +export const RealmCreate = () => { + const translate = useTranslate(); + const validateSlug = regex(/^[a-zA-Z0-9_-]+$/, 'error.invalid_slug'); + return ( + + + + } + label="ra.action.cancel" + /> + + } + > + + {translate('page.realms.create.title')} + + + {translate('page.realms.create.description')} + + + + + + + ); +}; + +export const RealmEdit = () => { + const translate = useTranslate(); + return ( + + + + } + label="ra.action.cancel" + /> + + } + > + + {translate('page.realms.edit.title')} + + + {translate('page.realms.edit.description')} + + + + + + ); +}; diff --git a/admin-console/src/setupTests.ts b/admin-console/src/setupTests.ts new file mode 100644 index 000000000..8f2609b7b --- /dev/null +++ b/admin-console/src/setupTests.ts @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom'; diff --git a/admin-console/src/utils.ts b/admin-console/src/utils.ts new file mode 100644 index 000000000..25f16ce44 --- /dev/null +++ b/admin-console/src/utils.ts @@ -0,0 +1,22 @@ +export class utils { + //deep copy an obj with nested props + public static deepCopy(source: T): T { + return Array.isArray(source) + ? source.map(i => this.deepCopy(i)) + : source && typeof source === 'object' + ? Object.getOwnPropertyNames(source).reduce((obj, prop) => { + Object.defineProperty( + obj, + prop, + Object.getOwnPropertyDescriptor(source, prop)! + ); + obj[prop] = this.deepCopy( + (source as { [key: string]: any })[prop] + ); + return obj; + }, Object.create(Object.getPrototypeOf(source))) + : (source as T); + } +} + +export default utils; diff --git a/admin-console/tsconfig.json b/admin-console/tsconfig.json new file mode 100644 index 000000000..a273b0cfc --- /dev/null +++ b/admin-console/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": [ + "src" + ] +} diff --git a/admin-console/yarn.lock b/admin-console/yarn.lock new file mode 100644 index 000000000..2be7f369d --- /dev/null +++ b/admin-console/yarn.lock @@ -0,0 +1,10093 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@adobe/css-tools@^4.0.1": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.1.0.tgz#417fef4a143f4396ad0b3b4351fee21323f15aa8" + integrity sha512-mMVJ/j/GbZ/De4ZHWbQAQO1J6iVnjtZLc9WEdkUQb8S/Bu2cAF2bETXUgMAdvMG3/ngtKmcNBe+Zms9bg6jnQQ== + +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@apideck/better-ajv-errors@^0.3.1": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz#957d4c28e886a64a8141f7522783be65733ff097" + integrity sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA== + dependencies: + json-schema "^0.4.0" + jsonpointer "^5.0.0" + leven "^3.1.0" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.8.3": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.1", "@babel/compat-data@^7.20.5": + version "7.20.14" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.14.tgz#4106fc8b755f3e3ee0a0a7c27dde5de1d2b2baf8" + integrity sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw== + +"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.12.3", "@babel/core@^7.16.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0": + version "7.20.12" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.12.tgz#7930db57443c6714ad216953d1356dac0eb8496d" + integrity sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.20.7" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-module-transforms" "^7.20.11" + "@babel/helpers" "^7.20.7" + "@babel/parser" "^7.20.7" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.12" + "@babel/types" "^7.20.7" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.0" + +"@babel/eslint-parser@^7.16.3": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz#4f68f6b0825489e00a24b41b6a1ae35414ecd2f4" + integrity sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ== + dependencies: + "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" + eslint-visitor-keys "^2.1.0" + semver "^6.3.0" + +"@babel/generator@^7.20.7", "@babel/generator@^7.7.2": + version "7.20.14" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.14.tgz#9fa772c9f86a46c6ac9b321039400712b96f64ce" + integrity sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg== + dependencies: + "@babel/types" "^7.20.7" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz#acd4edfd7a566d1d51ea975dff38fd52906981bb" + integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.20.0", "@babel/helper-compilation-targets@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz#a6cd33e93629f5eb473b021aac05df62c4cd09bb" + integrity sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ== + dependencies: + "@babel/compat-data" "^7.20.5" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.21.3" + lru-cache "^5.1.1" + semver "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.20.12", "@babel/helper-create-class-features-plugin@^7.20.5", "@babel/helper-create-class-features-plugin@^7.20.7": + version "7.20.12" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz#4349b928e79be05ed2d1643b20b99bb87c503819" + integrity sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-member-expression-to-functions" "^7.20.7" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-replace-supers" "^7.20.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + "@babel/helper-split-export-declaration" "^7.18.6" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz#5ea79b59962a09ec2acf20a963a01ab4d076ccca" + integrity sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + regexpu-core "^5.2.1" + +"@babel/helper-define-polyfill-provider@^0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz#8612e55be5d51f0cd1f36b4a5a83924e89884b7a" + integrity sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww== + dependencies: + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + +"@babel/helper-explode-assignable-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096" + integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c" + integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w== + dependencies: + "@babel/template" "^7.18.10" + "@babel/types" "^7.19.0" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-member-expression-to-functions@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz#a6f26e919582275a93c3aa6594756d71b0bb7f05" + integrity sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw== + dependencies: + "@babel/types" "^7.20.7" + +"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11": + version "7.20.11" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz#df4c7af713c557938c50ea3ad0117a7944b2f1b0" + integrity sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.20.2" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.19.1" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.10" + "@babel/types" "^7.20.7" + +"@babel/helper-optimise-call-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" + integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" + integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== + +"@babel/helper-remap-async-to-generator@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" + integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-wrap-function" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz#243ecd2724d2071532b2c8ad2f0f9f083bcae331" + integrity sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.20.7" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.7" + "@babel/types" "^7.20.7" + +"@babel/helper-simple-access@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz#0ab452687fe0c2cfb1e2b9e0015de07fc2d62dd9" + integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== + dependencies: + "@babel/types" "^7.20.2" + +"@babel/helper-skip-transparent-expression-wrappers@^7.20.0": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz#fbe4c52f60518cab8140d77101f0e63a8a230684" + integrity sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg== + dependencies: + "@babel/types" "^7.20.0" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.19.4": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" + integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== + +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helper-wrap-function@^7.18.9": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz#75e2d84d499a0ab3b31c33bcfe59d6b8a45f62e3" + integrity sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q== + dependencies: + "@babel/helper-function-name" "^7.19.0" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.20.5" + "@babel/types" "^7.20.5" + +"@babel/helpers@^7.20.7": + version "7.20.13" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.13.tgz#e3cb731fb70dc5337134cadc24cbbad31cc87ad2" + integrity sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg== + dependencies: + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.13" + "@babel/types" "^7.20.7" + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.13", "@babel/parser@^7.20.7": + version "7.20.13" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.13.tgz#ddf1eb5a813588d2fb1692b70c6fce75b945c088" + integrity sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" + integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz#d9c85589258539a22a901033853101a6198d4ef1" + integrity sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + "@babel/plugin-proposal-optional-chaining" "^7.20.7" + +"@babel/plugin-proposal-async-generator-functions@^7.20.1": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz#bfb7276d2d573cb67ba379984a2334e262ba5326" + integrity sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-remap-async-to-generator" "^7.18.9" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.16.0", "@babel/plugin-proposal-class-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" + integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-class-static-block@^7.18.6": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz#92592e9029b13b15be0f7ce6a7aedc2879ca45a7" + integrity sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.20.7" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-decorators@^7.16.4": + version "7.20.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.13.tgz#b6bea3b18e88443688fa7ed2cc06d2c60da9f4a7" + integrity sha512-7T6BKHa9Cpd7lCueHBBzP0nkXNina+h5giOZw+a8ZpMfPFY19VjJAjIxyFHuWkhCWgL6QMqRiY/wB1fLXzm6Mw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.20.12" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-replace-supers" "^7.20.7" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/plugin-syntax-decorators" "^7.19.0" + +"@babel/plugin-proposal-dynamic-import@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz#72bcf8d408799f547d759298c3c27c7e7faa4d94" + integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz#5f7313ab348cdb19d590145f9247540e94761203" + integrity sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz#7e8788c1811c393aff762817e7dbf1ebd0c05f0b" + integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.18.9": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz#dfbcaa8f7b4d37b51e8bfb46d94a5aea2bb89d83" + integrity sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.16.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" + integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.16.0", "@babel/plugin-proposal-numeric-separator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" + integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.20.2": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" + integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== + dependencies: + "@babel/compat-data" "^7.20.5" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.20.7" + +"@babel/plugin-proposal-optional-catch-binding@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb" + integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.16.0", "@babel/plugin-proposal-optional-chaining@^7.18.9", "@babel/plugin-proposal-optional-chaining@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz#49f2b372519ab31728cc14115bb0998b15bfda55" + integrity sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.16.0", "@babel/plugin-proposal-private-methods@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea" + integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-private-property-in-object@^7.18.6": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz#309c7668f2263f1c711aa399b5a9a6291eef6135" + integrity sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.20.5" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e" + integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-decorators@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz#5f13d1d8fce96951bea01a10424463c9a5b3a599" + integrity sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ== + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-flow@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz#774d825256f2379d06139be0c723c4dd444f3ca1" + integrity sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-import-assertions@^7.20.0": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz#bb50e0d4bea0957235390641209394e87bdb9cc4" + integrity sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ== + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.17.12", "@babel/plugin-syntax-jsx@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" + integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.20.0", "@babel/plugin-syntax-typescript@^7.7.2": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz#4e9a0cfc769c85689b77a2e642d24e9f697fc8c7" + integrity sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-transform-arrow-functions@^7.18.6": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz#bea332b0e8b2dab3dafe55a163d8227531ab0551" + integrity sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-async-to-generator@^7.18.6": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz#dfee18623c8cb31deb796aa3ca84dda9cea94354" + integrity sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q== + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-remap-async-to-generator" "^7.18.9" + +"@babel/plugin-transform-block-scoped-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8" + integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-block-scoping@^7.20.2": + version "7.20.14" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.14.tgz#2f5025f01713ba739daf737997308e0d29d1dd75" + integrity sha512-sMPepQtsOs5fM1bwNvuJJHvaCfOEQfmc01FGw0ELlTpTJj5Ql/zuNRRldYhAPys4ghXdBIQJbRVYi44/7QflQQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-classes@^7.20.2": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz#f438216f094f6bb31dc266ebfab8ff05aecad073" + integrity sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-replace-supers" "^7.20.7" + "@babel/helper-split-export-declaration" "^7.18.6" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.18.9": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz#704cc2fd155d1c996551db8276d55b9d46e4d0aa" + integrity sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/template" "^7.20.7" + +"@babel/plugin-transform-destructuring@^7.20.2": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz#8bda578f71620c7de7c93af590154ba331415454" + integrity sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8" + integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-duplicate-keys@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz#687f15ee3cdad6d85191eb2a372c4528eaa0ae0e" + integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-exponentiation-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd" + integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-flow-strip-types@^7.16.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz#e9e8606633287488216028719638cbbb2f2dde8f" + integrity sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg== + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/plugin-syntax-flow" "^7.18.6" + +"@babel/plugin-transform-for-of@^7.18.8": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz#6ef8a50b244eb6a0bdbad0c7c61877e4e30097c1" + integrity sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0" + integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ== + dependencies: + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc" + integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-member-expression-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e" + integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-modules-amd@^7.19.6": + version "7.20.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz#3daccca8e4cc309f03c3a0c4b41dc4b26f55214a" + integrity sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g== + dependencies: + "@babel/helper-module-transforms" "^7.20.11" + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-modules-commonjs@^7.19.6": + version "7.20.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz#8cb23010869bf7669fd4b3098598b6b2be6dc607" + integrity sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw== + dependencies: + "@babel/helper-module-transforms" "^7.20.11" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-simple-access" "^7.20.2" + +"@babel/plugin-transform-modules-systemjs@^7.19.6": + version "7.20.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz#467ec6bba6b6a50634eea61c9c232654d8a4696e" + integrity sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw== + dependencies: + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-module-transforms" "^7.20.11" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-validator-identifier" "^7.19.1" + +"@babel/plugin-transform-modules-umd@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz#81d3832d6034b75b54e62821ba58f28ed0aab4b9" + integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ== + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.19.1": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz#626298dd62ea51d452c3be58b285d23195ba69a8" + integrity sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.20.5" + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-new-target@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz#d128f376ae200477f37c4ddfcc722a8a1b3246a8" + integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-object-super@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c" + integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" + +"@babel/plugin-transform-parameters@^7.20.1", "@babel/plugin-transform-parameters@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz#0ee349e9d1bc96e78e3b37a7af423a4078a7083f" + integrity sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-property-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3" + integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-constant-elements@^7.12.1": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.20.2.tgz#3f02c784e0b711970d7d8ccc96c4359d64e27ac7" + integrity sha512-KS/G8YI8uwMGKErLFOHS/ekhqdHhpEloxs43NecQHVgo2QuQSyJhGIY1fL8UGl9wy5ItVwwoUL4YxVqsplGq2g== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-react-display-name@^7.16.0", "@babel/plugin-transform-react-display-name@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz#8b1125f919ef36ebdfff061d664e266c666b9415" + integrity sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx-development@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5" + integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.18.6" + +"@babel/plugin-transform-react-jsx@^7.18.6": + version "7.20.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.20.13.tgz#f950f0b0c36377503d29a712f16287cedf886cbb" + integrity sha512-MmTZx/bkUrfJhhYAYt3Urjm+h8DQGrPrnKQ94jLo7NLuOU+T89a7IByhKmrb8SKhrIYIQ0FN0CHMbnFRen4qNw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-jsx" "^7.18.6" + "@babel/types" "^7.20.7" + +"@babel/plugin-transform-react-pure-annotations@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz#561af267f19f3e5d59291f9950fd7b9663d0d844" + integrity sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-regenerator@^7.18.6": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz#57cda588c7ffb7f4f8483cc83bdcea02a907f04d" + integrity sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + regenerator-transform "^0.15.1" + +"@babel/plugin-transform-reserved-words@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz#b1abd8ebf8edaa5f7fe6bbb8d2133d23b6a6f76a" + integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-runtime@^7.16.4": + version "7.19.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz#9d2a9dbf4e12644d6f46e5e75bfbf02b5d6e9194" + integrity sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw== + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.19.0" + babel-plugin-polyfill-corejs2 "^0.3.3" + babel-plugin-polyfill-corejs3 "^0.6.0" + babel-plugin-polyfill-regenerator "^0.4.1" + semver "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9" + integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-spread@^7.19.0": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz#c2d83e0b99d3bf83e07b11995ee24bf7ca09401e" + integrity sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + +"@babel/plugin-transform-sticky-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc" + integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-template-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e" + integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-typeof-symbol@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz#c8cea68263e45addcd6afc9091429f80925762c0" + integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-typescript@^7.18.6": + version "7.20.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.13.tgz#e3581b356b8694f6ff450211fe6774eaff8d25ab" + integrity sha512-O7I/THxarGcDZxkgWKMUrk7NK1/WbHAg3Xx86gqS6x9MTrNL6AwIluuZ96ms4xeDe6AVx6rjHbWHP7x26EPQBA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.20.12" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-typescript" "^7.20.0" + +"@babel/plugin-transform-unicode-escapes@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz#1ecfb0eda83d09bbcb77c09970c2dd55832aa246" + integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-unicode-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca" + integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.12.1", "@babel/preset-env@^7.16.4": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.20.2.tgz#9b1642aa47bb9f43a86f9630011780dab7f86506" + integrity sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg== + dependencies: + "@babel/compat-data" "^7.20.1" + "@babel/helper-compilation-targets" "^7.20.0" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9" + "@babel/plugin-proposal-async-generator-functions" "^7.20.1" + "@babel/plugin-proposal-class-properties" "^7.18.6" + "@babel/plugin-proposal-class-static-block" "^7.18.6" + "@babel/plugin-proposal-dynamic-import" "^7.18.6" + "@babel/plugin-proposal-export-namespace-from" "^7.18.9" + "@babel/plugin-proposal-json-strings" "^7.18.6" + "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" + "@babel/plugin-proposal-numeric-separator" "^7.18.6" + "@babel/plugin-proposal-object-rest-spread" "^7.20.2" + "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" + "@babel/plugin-proposal-optional-chaining" "^7.18.9" + "@babel/plugin-proposal-private-methods" "^7.18.6" + "@babel/plugin-proposal-private-property-in-object" "^7.18.6" + "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.20.0" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.18.6" + "@babel/plugin-transform-async-to-generator" "^7.18.6" + "@babel/plugin-transform-block-scoped-functions" "^7.18.6" + "@babel/plugin-transform-block-scoping" "^7.20.2" + "@babel/plugin-transform-classes" "^7.20.2" + "@babel/plugin-transform-computed-properties" "^7.18.9" + "@babel/plugin-transform-destructuring" "^7.20.2" + "@babel/plugin-transform-dotall-regex" "^7.18.6" + "@babel/plugin-transform-duplicate-keys" "^7.18.9" + "@babel/plugin-transform-exponentiation-operator" "^7.18.6" + "@babel/plugin-transform-for-of" "^7.18.8" + "@babel/plugin-transform-function-name" "^7.18.9" + "@babel/plugin-transform-literals" "^7.18.9" + "@babel/plugin-transform-member-expression-literals" "^7.18.6" + "@babel/plugin-transform-modules-amd" "^7.19.6" + "@babel/plugin-transform-modules-commonjs" "^7.19.6" + "@babel/plugin-transform-modules-systemjs" "^7.19.6" + "@babel/plugin-transform-modules-umd" "^7.18.6" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.19.1" + "@babel/plugin-transform-new-target" "^7.18.6" + "@babel/plugin-transform-object-super" "^7.18.6" + "@babel/plugin-transform-parameters" "^7.20.1" + "@babel/plugin-transform-property-literals" "^7.18.6" + "@babel/plugin-transform-regenerator" "^7.18.6" + "@babel/plugin-transform-reserved-words" "^7.18.6" + "@babel/plugin-transform-shorthand-properties" "^7.18.6" + "@babel/plugin-transform-spread" "^7.19.0" + "@babel/plugin-transform-sticky-regex" "^7.18.6" + "@babel/plugin-transform-template-literals" "^7.18.9" + "@babel/plugin-transform-typeof-symbol" "^7.18.9" + "@babel/plugin-transform-unicode-escapes" "^7.18.10" + "@babel/plugin-transform-unicode-regex" "^7.18.6" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.20.2" + babel-plugin-polyfill-corejs2 "^0.3.3" + babel-plugin-polyfill-corejs3 "^0.6.0" + babel-plugin-polyfill-regenerator "^0.4.1" + core-js-compat "^3.25.1" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-react@^7.12.5", "@babel/preset-react@^7.16.0": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.18.6.tgz#979f76d6277048dc19094c217b507f3ad517dd2d" + integrity sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-transform-react-display-name" "^7.18.6" + "@babel/plugin-transform-react-jsx" "^7.18.6" + "@babel/plugin-transform-react-jsx-development" "^7.18.6" + "@babel/plugin-transform-react-pure-annotations" "^7.18.6" + +"@babel/preset-typescript@^7.16.0": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz#ce64be3e63eddc44240c6358daefac17b3186399" + integrity sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-transform-typescript" "^7.18.6" + +"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.6", "@babel/runtime@^7.20.7", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.20.13" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.13.tgz#7055ab8a7cff2b8f6058bf6ae45ff84ad2aded4b" + integrity sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.3.3": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" + integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + +"@babel/traverse@^7.20.10", "@babel/traverse@^7.20.12", "@babel/traverse@^7.20.13", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.7.2": + version "7.20.13" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.13.tgz#817c1ba13d11accca89478bd5481b2d168d07473" + integrity sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.20.7" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.20.13" + "@babel/types" "^7.20.7" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f" + integrity sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg== + dependencies: + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@csstools/normalize.css@*": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-12.0.0.tgz#a9583a75c3f150667771f30b60d9f059473e62c4" + integrity sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg== + +"@csstools/postcss-cascade-layers@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz#8a997edf97d34071dd2e37ea6022447dd9e795ad" + integrity sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA== + dependencies: + "@csstools/selector-specificity" "^2.0.2" + postcss-selector-parser "^6.0.10" + +"@csstools/postcss-color-function@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz#2bd36ab34f82d0497cfacdc9b18d34b5e6f64b6b" + integrity sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^1.1.0" + postcss-value-parser "^4.2.0" + +"@csstools/postcss-font-format-keywords@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz#677b34e9e88ae997a67283311657973150e8b16a" + integrity sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-hwb-function@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz#ab54a9fce0ac102c754854769962f2422ae8aa8b" + integrity sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-ic-unit@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz#28237d812a124d1a16a5acc5c3832b040b303e58" + integrity sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^1.1.0" + postcss-value-parser "^4.2.0" + +"@csstools/postcss-is-pseudo-class@^2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz#846ae6c0d5a1eaa878fce352c544f9c295509cd1" + integrity sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA== + dependencies: + "@csstools/selector-specificity" "^2.0.0" + postcss-selector-parser "^6.0.10" + +"@csstools/postcss-nested-calc@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz#d7e9d1d0d3d15cf5ac891b16028af2a1044d0c26" + integrity sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-normalize-display-values@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz#15da54a36e867b3ac5163ee12c1d7f82d4d612c3" + integrity sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-oklab-function@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz#88cee0fbc8d6df27079ebd2fa016ee261eecf844" + integrity sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^1.1.0" + postcss-value-parser "^4.2.0" + +"@csstools/postcss-progressive-custom-properties@^1.1.0", "@csstools/postcss-progressive-custom-properties@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz#542292558384361776b45c85226b9a3a34f276fa" + integrity sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-stepped-value-functions@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz#f8772c3681cc2befed695e2b0b1d68e22f08c4f4" + integrity sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-text-decoration-shorthand@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz#ea96cfbc87d921eca914d3ad29340d9bcc4c953f" + integrity sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-trigonometric-functions@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz#94d3e4774c36d35dcdc88ce091336cb770d32756" + integrity sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-unset-value@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz#c99bb70e2cdc7312948d1eb41df2412330b81f77" + integrity sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g== + +"@csstools/selector-specificity@^2.0.0", "@csstools/selector-specificity@^2.0.2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.1.1.tgz#c9c61d9fe5ca5ac664e1153bb0aa0eba1c6d6308" + integrity sha512-jwx+WCqszn53YHOfvFMJJRd/B2GqkCBt+1MJSG6o5/s8+ytHMvDZXsJgUEWLk12UnLd7HYKac4BYU5i/Ron1Cw== + +"@emotion/babel-plugin@^11.10.5": + version "11.10.5" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz#65fa6e1790ddc9e23cc22658a4c5dea423c55c3c" + integrity sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/plugin-syntax-jsx" "^7.17.12" + "@babel/runtime" "^7.18.3" + "@emotion/hash" "^0.9.0" + "@emotion/memoize" "^0.8.0" + "@emotion/serialize" "^1.1.1" + babel-plugin-macros "^3.1.0" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.1.3" + +"@emotion/cache@^11.10.5": + version "11.10.5" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.5.tgz#c142da9351f94e47527ed458f7bbbbe40bb13c12" + integrity sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA== + dependencies: + "@emotion/memoize" "^0.8.0" + "@emotion/sheet" "^1.2.1" + "@emotion/utils" "^1.2.0" + "@emotion/weak-memoize" "^0.3.0" + stylis "4.1.3" + +"@emotion/hash@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7" + integrity sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ== + +"@emotion/is-prop-valid@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz#7f2d35c97891669f7e276eb71c83376a5dc44c83" + integrity sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg== + dependencies: + "@emotion/memoize" "^0.8.0" + +"@emotion/memoize@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f" + integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA== + +"@emotion/react@^11.4.1": + version "11.10.5" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.5.tgz#95fff612a5de1efa9c0d535384d3cfa115fe175d" + integrity sha512-TZs6235tCJ/7iF6/rvTaOH4oxQg2gMAcdHemjwLKIjKz4rRuYe1HJ2TQJKnAcRAfOUDdU8XoDadCe1rl72iv8A== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.10.5" + "@emotion/cache" "^11.10.5" + "@emotion/serialize" "^1.1.1" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0" + "@emotion/utils" "^1.2.0" + "@emotion/weak-memoize" "^0.3.0" + hoist-non-react-statics "^3.3.1" + +"@emotion/serialize@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.1.tgz#0595701b1902feded8a96d293b26be3f5c1a5cf0" + integrity sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA== + dependencies: + "@emotion/hash" "^0.9.0" + "@emotion/memoize" "^0.8.0" + "@emotion/unitless" "^0.8.0" + "@emotion/utils" "^1.2.0" + csstype "^3.0.2" + +"@emotion/sheet@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.1.tgz#0767e0305230e894897cadb6c8df2c51e61a6c2c" + integrity sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA== + +"@emotion/styled@^11.3.0": + version "11.10.5" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.10.5.tgz#1fe7bf941b0909802cb826457e362444e7e96a79" + integrity sha512-8EP6dD7dMkdku2foLoruPCNkRevzdcBaY6q0l0OsbyJK+x8D9HWjX27ARiSIKNF634hY9Zdoedh8bJCiva8yZw== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.10.5" + "@emotion/is-prop-valid" "^1.2.0" + "@emotion/serialize" "^1.1.1" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0" + "@emotion/utils" "^1.2.0" + +"@emotion/unitless@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db" + integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw== + +"@emotion/use-insertion-effect-with-fallbacks@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz#ffadaec35dbb7885bd54de3fa267ab2f860294df" + integrity sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A== + +"@emotion/utils@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561" + integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw== + +"@emotion/weak-memoize@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" + integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== + +"@eslint/eslintrc@^1.4.1": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e" + integrity sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.4.0" + globals "^13.19.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" + +"@gfx/zopfli@^1.0.15": + version "1.0.15" + resolved "https://registry.yarnpkg.com/@gfx/zopfli/-/zopfli-1.0.15.tgz#00720b4f6a4d5ceeb585a5d6dd672b48bd4fc755" + integrity sha512-7mBgpi7UD82fsff5ThQKet0uBTl4BYerQuc+/qA1ELTwWEiIedRTcD3JgiUu9wwZ2kytW8JOb165rSdAt8PfcQ== + dependencies: + base64-js "^1.3.0" + +"@humanwhocodes/config-array@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" + integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba" + integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + +"@jest/console@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-28.1.3.tgz#2030606ec03a18c31803b8a36382762e447655df" + integrity sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + slash "^3.0.0" + +"@jest/core@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626" + integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/reporters" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^27.5.1" + jest-config "^27.5.1" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-resolve-dependencies "^27.5.1" + jest-runner "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + jest-watcher "^27.5.1" + micromatch "^4.0.4" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" + integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== + dependencies: + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + +"@jest/expect-utils@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.4.1.tgz#105b9f3e2c48101f09cae2f0a4d79a1b3a419cbb" + integrity sha512-w6YJMn5DlzmxjO00i9wu2YSozUYRBhIoJ6nQwpMYcBMtiqMGJm1QBzOf6DDgRao8dbtpDoaqLg6iiQTvv0UHhQ== + dependencies: + jest-get-type "^29.2.0" + +"@jest/fake-timers@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" + integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== + dependencies: + "@jest/types" "^27.5.1" + "@sinonjs/fake-timers" "^8.0.1" + "@types/node" "*" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-util "^27.5.1" + +"@jest/globals@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b" + integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/types" "^27.5.1" + expect "^27.5.1" + +"@jest/reporters@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04" + integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-haste-map "^27.5.1" + jest-resolve "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^8.1.0" + +"@jest/schemas@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-28.1.3.tgz#ad8b86a66f11f33619e3d7e1dcddd7f2d40ff905" + integrity sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg== + dependencies: + "@sinclair/typebox" "^0.24.1" + +"@jest/schemas@^29.4.0": + version "29.4.0" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.0.tgz#0d6ad358f295cc1deca0b643e6b4c86ebd539f17" + integrity sha512-0E01f/gOZeNTG76i5eWWSupvSHaIINrTie7vCyjiYFKgzNdyEGd12BUv4oNBFHOqlHDbtoJi3HrQ38KCC90NsQ== + dependencies: + "@sinclair/typebox" "^0.25.16" + +"@jest/source-map@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" + integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.9" + source-map "^0.6.0" + +"@jest/test-result@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb" + integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag== + dependencies: + "@jest/console" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-result@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-28.1.3.tgz#5eae945fd9f4b8fcfce74d239e6f725b6bf076c5" + integrity sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg== + dependencies: + "@jest/console" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b" + integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ== + dependencies: + "@jest/test-result" "^27.5.1" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-runtime "^27.5.1" + +"@jest/transform@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" + integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.5.1" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-regex-util "^27.5.1" + jest-util "^27.5.1" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" + integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + +"@jest/types@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.3.tgz#b05de80996ff12512bc5ceb1d208285a7d11748b" + integrity sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ== + dependencies: + "@jest/schemas" "^28.1.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jest/types@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.4.1.tgz#f9f83d0916f50696661da72766132729dcb82ecb" + integrity sha512-zbrAXDUOnpJ+FMST2rV7QZOgec8rskg2zv8g2ajeqitp4tvZiyqTCYXANrKsM+ryj5o+LI+ZN2EgU9drrkiwSA== + dependencies: + "@jest/schemas" "^29.4.0" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.17" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" + integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@leichtgewicht/ip-codec@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" + integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== + +"@mui/base@5.0.0-alpha.115": + version "5.0.0-alpha.115" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.115.tgz#582b147fda56fe52d561fe9f64406e036d882338" + integrity sha512-OGQ84whT/yNYd6xKCGGS6MxqEfjVjk5esXM7HP6bB2Rim7QICUapxZt4nm8q39fpT08rNDkv3xPVqDDwRdRg1g== + dependencies: + "@babel/runtime" "^7.20.7" + "@emotion/is-prop-valid" "^1.2.0" + "@mui/types" "^7.2.3" + "@mui/utils" "^5.11.2" + "@popperjs/core" "^2.11.6" + clsx "^1.2.1" + prop-types "^15.8.1" + react-is "^18.2.0" + +"@mui/base@5.0.0-alpha.116": + version "5.0.0-alpha.116" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.116.tgz#c167a66b7232088b4bcd97ba36096a357c6e4fb9" + integrity sha512-VwhifWdrfHc4/ZdqRZ4Gf+7P39sovNN24By1YVZdvJ9fvp0Sr8sNftGUCjYXXz+xCXVBQDXvhfxMwZrj2MvJvA== + dependencies: + "@babel/runtime" "^7.20.7" + "@emotion/is-prop-valid" "^1.2.0" + "@mui/types" "^7.2.3" + "@mui/utils" "^5.11.7" + "@popperjs/core" "^2.11.6" + clsx "^1.2.1" + prop-types "^15.8.1" + react-is "^18.2.0" + +"@mui/core-downloads-tracker@^5.11.6": + version "5.11.6" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.6.tgz#79a60c0d95a08859cccd62a8d9a5336ef477a840" + integrity sha512-lbD3qdafBOf2dlqKhOcVRxaPAujX+9UlPC6v8iMugMeAXe0TCgU3QbGXY3zrJsu6ex64WYDpH4y1+WOOBmWMuA== + +"@mui/core-downloads-tracker@^5.11.7": + version "5.11.7" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.7.tgz#b3a3aad64c6b69f6165d7a00c0d9cfeacbe357a2" + integrity sha512-lZgX7XQTk0zVcpwEa80r+T4y09dosnUxWvFPSikU/2Hh5wnyNOek8WfJwGCNsaRiXJHMi5eHY+z8oku4u5lgNw== + +"@mui/icons-material@^5.0.1", "@mui/icons-material@^5.11.0": + version "5.11.0" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.11.0.tgz#9ea6949278b2266d2683866069cd43009eaf6464" + integrity sha512-I2LaOKqO8a0xcLGtIozC9xoXjZAto5G5gh0FYUMAlbsIHNHIjn4Xrw9rvjY20vZonyiGrZNMAlAXYkY6JvhF6A== + dependencies: + "@babel/runtime" "^7.20.6" + +"@mui/material@^5.0.2": + version "5.11.6" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.11.6.tgz#0055e7bdf5f89bb7f2a5cf0a3252dadfc9122c50" + integrity sha512-MzkkL5KC2PCkFiv8cLpkzgLUPXSrAtnvJBR0emV7mLVWbkwV3n5832vjBx154B6R032fHjFTziTh7YEb50nK6Q== + dependencies: + "@babel/runtime" "^7.20.7" + "@mui/base" "5.0.0-alpha.115" + "@mui/core-downloads-tracker" "^5.11.6" + "@mui/system" "^5.11.5" + "@mui/types" "^7.2.3" + "@mui/utils" "^5.11.2" + "@types/react-transition-group" "^4.4.5" + clsx "^1.2.1" + csstype "^3.1.1" + prop-types "^15.8.1" + react-is "^18.2.0" + react-transition-group "^4.4.5" + +"@mui/material@^5.11.7": + version "5.11.7" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.11.7.tgz#d460c7239013a57cc2aa3d2bbe14ba875b29d7cb" + integrity sha512-wDv7Pc6kMe9jeWkmCLt4JChd1lPc2u23JQHpB35L2VwQowpNFoDfIwqi0sYCnZTMKlRc7lza8LqwSwHl2G52Rw== + dependencies: + "@babel/runtime" "^7.20.7" + "@mui/base" "5.0.0-alpha.116" + "@mui/core-downloads-tracker" "^5.11.7" + "@mui/system" "^5.11.7" + "@mui/types" "^7.2.3" + "@mui/utils" "^5.11.7" + "@types/react-transition-group" "^4.4.5" + clsx "^1.2.1" + csstype "^3.1.1" + prop-types "^15.8.1" + react-is "^18.2.0" + react-transition-group "^4.4.5" + +"@mui/private-theming@^5.11.2": + version "5.11.2" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.11.2.tgz#93eafb317070888a988efa8d6a9ec1f69183a606" + integrity sha512-qZwMaqRFPwlYmqwVKblKBGKtIjJRAj3nsvX93pOmatsXyorW7N/0IPE/swPgz1VwChXhHO75DwBEx8tB+aRMNg== + dependencies: + "@babel/runtime" "^7.20.7" + "@mui/utils" "^5.11.2" + prop-types "^15.8.1" + +"@mui/private-theming@^5.11.7": + version "5.11.7" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.11.7.tgz#e92b87d6ea68ae5a23d0f0d9d248361b889a98db" + integrity sha512-XzRTSZdc8bhuUdjablTNv3kFkZ/XIMlKkOqqJCU0G8W3tWGXpau2DXkafPd1ddjPhF9zF3qLKNGgKCChYItjgA== + dependencies: + "@babel/runtime" "^7.20.7" + "@mui/utils" "^5.11.7" + prop-types "^15.8.1" + +"@mui/styled-engine@^5.11.0": + version "5.11.0" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.11.0.tgz#79afb30c612c7807c4b77602cf258526d3997c7b" + integrity sha512-AF06K60Zc58qf0f7X+Y/QjaHaZq16znliLnGc9iVrV/+s8Ln/FCoeNuFvhlCbZZQ5WQcJvcy59zp0nXrklGGPQ== + dependencies: + "@babel/runtime" "^7.20.6" + "@emotion/cache" "^11.10.5" + csstype "^3.1.1" + prop-types "^15.8.1" + +"@mui/system@^5.11.5": + version "5.11.5" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.11.5.tgz#c880199634708c866063396f88d3fdd4c1dfcb48" + integrity sha512-KNVsJ0sgRRp2XBqhh4wPS5aacteqjwxgiYTVwVnll2fgkgunZKo3DsDiGMrFlCg25ZHA3Ax58txWGE9w58zp0w== + dependencies: + "@babel/runtime" "^7.20.7" + "@mui/private-theming" "^5.11.2" + "@mui/styled-engine" "^5.11.0" + "@mui/types" "^7.2.3" + "@mui/utils" "^5.11.2" + clsx "^1.2.1" + csstype "^3.1.1" + prop-types "^15.8.1" + +"@mui/system@^5.11.7": + version "5.11.7" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.11.7.tgz#5e550c621733a18cd437678f11dcd1c3468129d0" + integrity sha512-uGB6hBxGlAdlmbLdTtUZYNPXkgQGGnKxHdkRATqsu7UlCxNsc/yS5NCEWy/3c4pnelD1LDLD39WrntP9mwhfkQ== + dependencies: + "@babel/runtime" "^7.20.7" + "@mui/private-theming" "^5.11.7" + "@mui/styled-engine" "^5.11.0" + "@mui/types" "^7.2.3" + "@mui/utils" "^5.11.7" + clsx "^1.2.1" + csstype "^3.1.1" + prop-types "^15.8.1" + +"@mui/types@^7.2.3": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.3.tgz#06faae1c0e2f3a31c86af6f28b3a4a42143670b9" + integrity sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw== + +"@mui/utils@^5.11.2": + version "5.11.2" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.11.2.tgz#29764311acb99425159b159b1cb382153ad9be1f" + integrity sha512-AyizuHHlGdAtH5hOOXBW3kriuIwUIKUIgg0P7LzMvzf6jPhoQbENYqY6zJqfoZ7fAWMNNYT8mgN5EftNGzwE2w== + dependencies: + "@babel/runtime" "^7.20.7" + "@types/prop-types" "^15.7.5" + "@types/react-is" "^16.7.1 || ^17.0.0" + prop-types "^15.8.1" + react-is "^18.2.0" + +"@mui/utils@^5.11.7": + version "5.11.7" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.11.7.tgz#a343a5d375b4140c875bf4c96825c1a148994800" + integrity sha512-8uyNDeVHZA804Ego20Erv8TpxlbqTe/EbhTI2H1UYr4/RiIbBprat8W4Qqr2UQIsC/b3DLz+0RQ6R/E5BxEcLA== + dependencies: + "@babel/runtime" "^7.20.7" + "@types/prop-types" "^15.7.5" + "@types/react-is" "^16.7.1 || ^17.0.0" + prop-types "^15.8.1" + react-is "^18.2.0" + +"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": + version "5.1.1-v1" + resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" + integrity sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg== + dependencies: + eslint-scope "5.1.1" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@pmmmwh/react-refresh-webpack-plugin@^0.5.3": + version "0.5.10" + resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz#2eba163b8e7dbabb4ce3609ab5e32ab63dda3ef8" + integrity sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA== + dependencies: + ansi-html-community "^0.0.8" + common-path-prefix "^3.0.0" + core-js-pure "^3.23.3" + error-stack-parser "^2.0.6" + find-up "^5.0.0" + html-entities "^2.1.0" + loader-utils "^2.0.4" + schema-utils "^3.0.0" + source-map "^0.7.3" + +"@popperjs/core@^2.11.6": + version "2.11.6" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" + integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== + +"@remix-run/router@1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.3.1.tgz#3bb0b6ddc0a276e8dc1138d08f63035e4e23e8bf" + integrity sha512-+eun1Wtf72RNRSqgU7qM2AMX/oHp+dnx7BHk1qhK5ZHzdHTUU4LA1mGG1vT+jMc8sbhG3orvsfOmryjzx2PzQw== + +"@rollup/plugin-babel@^5.2.0": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283" + integrity sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q== + dependencies: + "@babel/helper-module-imports" "^7.10.4" + "@rollup/pluginutils" "^3.1.0" + +"@rollup/plugin-node-resolve@^11.2.1": + version "11.2.1" + resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz#82aa59397a29cd4e13248b106e6a4a1880362a60" + integrity sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg== + dependencies: + "@rollup/pluginutils" "^3.1.0" + "@types/resolve" "1.17.1" + builtin-modules "^3.1.0" + deepmerge "^4.2.2" + is-module "^1.0.0" + resolve "^1.19.0" + +"@rollup/plugin-replace@^2.4.1": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz#a2d539314fbc77c244858faa523012825068510a" + integrity sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg== + dependencies: + "@rollup/pluginutils" "^3.1.0" + magic-string "^0.25.7" + +"@rollup/pluginutils@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" + integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== + dependencies: + "@types/estree" "0.0.39" + estree-walker "^1.0.1" + picomatch "^2.2.2" + +"@rushstack/eslint-patch@^1.1.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz#8be36a1f66f3265389e90b5f9c9962146758f728" + integrity sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg== + +"@sinclair/typebox@^0.24.1": + version "0.24.51" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f" + integrity sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA== + +"@sinclair/typebox@^0.25.16": + version "0.25.21" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.21.tgz#763b05a4b472c93a8db29b2c3e359d55b29ce272" + integrity sha512-gFukHN4t8K4+wVC+ECqeqwzBDeFeTzBXroBTqE6vcWrQGbEUpHO7LYdG0f4xnvYq4VOEwITSlHlp0JBAIFMS/g== + +"@sinonjs/commons@^1.7.0": + version "1.8.6" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9" + integrity sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" + integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@surma/rollup-plugin-off-main-thread@^2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz#ee34985952ca21558ab0d952f00298ad2190c053" + integrity sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ== + dependencies: + ejs "^3.1.6" + json5 "^2.2.0" + magic-string "^0.25.0" + string.prototype.matchall "^4.0.6" + +"@svgr/babel-plugin-add-jsx-attribute@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz#81ef61947bb268eb9d50523446f9c638fb355906" + integrity sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg== + +"@svgr/babel-plugin-remove-jsx-attribute@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz#6b2c770c95c874654fd5e1d5ef475b78a0a962ef" + integrity sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg== + +"@svgr/babel-plugin-remove-jsx-empty-expression@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz#25621a8915ed7ad70da6cea3d0a6dbc2ea933efd" + integrity sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA== + +"@svgr/babel-plugin-replace-jsx-attribute-value@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz#0b221fc57f9fcd10e91fe219e2cd0dd03145a897" + integrity sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ== + +"@svgr/babel-plugin-svg-dynamic-title@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz#139b546dd0c3186b6e5db4fefc26cb0baea729d7" + integrity sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg== + +"@svgr/babel-plugin-svg-em-dimensions@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz#6543f69526632a133ce5cabab965deeaea2234a0" + integrity sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw== + +"@svgr/babel-plugin-transform-react-native-svg@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz#00bf9a7a73f1cad3948cdab1f8dfb774750f8c80" + integrity sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q== + +"@svgr/babel-plugin-transform-svg-component@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz#583a5e2a193e214da2f3afeb0b9e8d3250126b4a" + integrity sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ== + +"@svgr/babel-preset@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-5.5.0.tgz#8af54f3e0a8add7b1e2b0fcd5a882c55393df327" + integrity sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig== + dependencies: + "@svgr/babel-plugin-add-jsx-attribute" "^5.4.0" + "@svgr/babel-plugin-remove-jsx-attribute" "^5.4.0" + "@svgr/babel-plugin-remove-jsx-empty-expression" "^5.0.1" + "@svgr/babel-plugin-replace-jsx-attribute-value" "^5.0.1" + "@svgr/babel-plugin-svg-dynamic-title" "^5.4.0" + "@svgr/babel-plugin-svg-em-dimensions" "^5.4.0" + "@svgr/babel-plugin-transform-react-native-svg" "^5.4.0" + "@svgr/babel-plugin-transform-svg-component" "^5.5.0" + +"@svgr/core@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/core/-/core-5.5.0.tgz#82e826b8715d71083120fe8f2492ec7d7874a579" + integrity sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ== + dependencies: + "@svgr/plugin-jsx" "^5.5.0" + camelcase "^6.2.0" + cosmiconfig "^7.0.0" + +"@svgr/hast-util-to-babel-ast@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz#5ee52a9c2533f73e63f8f22b779f93cd432a5461" + integrity sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ== + dependencies: + "@babel/types" "^7.12.6" + +"@svgr/plugin-jsx@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz#1aa8cd798a1db7173ac043466d7b52236b369000" + integrity sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA== + dependencies: + "@babel/core" "^7.12.3" + "@svgr/babel-preset" "^5.5.0" + "@svgr/hast-util-to-babel-ast" "^5.5.0" + svg-parser "^2.0.2" + +"@svgr/plugin-svgo@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz#02da55d85320549324e201c7b2e53bf431fcc246" + integrity sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ== + dependencies: + cosmiconfig "^7.0.0" + deepmerge "^4.2.2" + svgo "^1.2.2" + +"@svgr/webpack@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-5.5.0.tgz#aae858ee579f5fa8ce6c3166ef56c6a1b381b640" + integrity sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g== + dependencies: + "@babel/core" "^7.12.3" + "@babel/plugin-transform-react-constant-elements" "^7.12.1" + "@babel/preset-env" "^7.12.1" + "@babel/preset-react" "^7.12.5" + "@svgr/core" "^5.5.0" + "@svgr/plugin-jsx" "^5.5.0" + "@svgr/plugin-svgo" "^5.5.0" + loader-utils "^2.0.0" + +"@testing-library/dom@^8.5.0": + version "8.20.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.20.0.tgz#914aa862cef0f5e89b98cc48e3445c4c921010f6" + integrity sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/runtime" "^7.12.5" + "@types/aria-query" "^5.0.1" + aria-query "^5.0.0" + chalk "^4.1.0" + dom-accessibility-api "^0.5.9" + lz-string "^1.4.4" + pretty-format "^27.0.2" + +"@testing-library/jest-dom@^5.14.1": + version "5.16.5" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz#3912846af19a29b2dbf32a6ae9c31ef52580074e" + integrity sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA== + dependencies: + "@adobe/css-tools" "^4.0.1" + "@babel/runtime" "^7.9.2" + "@types/testing-library__jest-dom" "^5.9.1" + aria-query "^5.0.0" + chalk "^3.0.0" + css.escape "^1.5.1" + dom-accessibility-api "^0.5.6" + lodash "^4.17.15" + redent "^3.0.0" + +"@testing-library/react@^13.0.0": + version "13.4.0" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-13.4.0.tgz#6a31e3bf5951615593ad984e96b9e5e2d9380966" + integrity sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw== + dependencies: + "@babel/runtime" "^7.12.5" + "@testing-library/dom" "^8.5.0" + "@types/react-dom" "^18.0.0" + +"@testing-library/user-event@^13.2.1": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-13.5.0.tgz#69d77007f1e124d55314a2b73fd204b333b13295" + integrity sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg== + dependencies: + "@babel/runtime" "^7.12.5" + +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== + +"@types/aria-query@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.1.tgz#3286741fb8f1e1580ac28784add4c7a1d49bdfbc" + integrity sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q== + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.0.tgz#61bc5a4cae505ce98e1e36c5445e4bee060d8891" + integrity sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.18.3" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.3.tgz#dfc508a85781e5698d5b33443416b6268c4b3e8d" + integrity sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w== + dependencies: + "@babel/types" "^7.3.0" + +"@types/body-parser@*": + version "1.19.2" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" + integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/bonjour@^3.5.9": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.10.tgz#0f6aadfe00ea414edc86f5d106357cda9701e275" + integrity sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw== + dependencies: + "@types/node" "*" + +"@types/connect-history-api-fallback@^1.3.5": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz#d1f7a8a09d0ed5a57aee5ae9c18ab9b803205dae" + integrity sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw== + dependencies: + "@types/express-serve-static-core" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + +"@types/eslint-scope@^3.7.3": + version "3.7.4" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" + integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*", "@types/eslint@^7.29.0 || ^8.4.1": + version "8.4.10" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.10.tgz#19731b9685c19ed1552da7052b6f668ed7eb64bb" + integrity sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" + integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== + +"@types/estree@0.0.39": + version "0.0.39" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" + integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== + +"@types/estree@^0.0.51": + version "0.0.51" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" + integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== + +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.31": + version "4.17.33" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz#de35d30a9d637dc1450ad18dd583d75d5733d543" + integrity sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@*", "@types/express@^4.17.13": + version "4.17.16" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.16.tgz#986caf0b4b850611254505355daa24e1b8323de8" + integrity sha512-LkKpqRZ7zqXJuvoELakaFYuETHjZkSol8EV6cNnyishutDBCCdv6+dsKPbKkCcIk57qRphOLY5sEgClw1bO3gA== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.31" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/graceful-fs@^4.1.2": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" + integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== + dependencies: + "@types/node" "*" + +"@types/html-minifier-terser@^6.0.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" + integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== + +"@types/http-proxy@^1.17.8": + version "1.17.9" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.9.tgz#7f0e7931343761efde1e2bf48c40f02f3f75705a" + integrity sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@*": + version "29.4.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.4.0.tgz#a8444ad1704493e84dbf07bb05990b275b3b9206" + integrity sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/jest@^27.0.1": + version "27.5.2" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.5.2.tgz#ec49d29d926500ffb9fd22b84262e862049c026c" + integrity sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA== + dependencies: + jest-matcher-utils "^27.0.0" + pretty-format "^27.0.0" + +"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/mime@*": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" + integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== + +"@types/node@*": + version "18.11.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f" + integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA== + +"@types/node@^16.7.13": + version "16.18.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.11.tgz#cbb15c12ca7c16c85a72b6bdc4d4b01151bb3cae" + integrity sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/prettier@^2.1.5": + version "2.7.2" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" + integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg== + +"@types/prop-types@*", "@types/prop-types@^15.7.5": + version "15.7.5" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" + integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== + +"@types/q@^1.5.1": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" + integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== + +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + +"@types/react-dom@^18.0.0", "@types/react-dom@^18.0.10": + version "18.0.10" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.10.tgz#3b66dec56aa0f16a6cc26da9e9ca96c35c0b4352" + integrity sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg== + dependencies: + "@types/react" "*" + +"@types/react-is@^16.7.1 || ^17.0.0": + version "17.0.3" + resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-17.0.3.tgz#2d855ba575f2fc8d17ef9861f084acc4b90a137a" + integrity sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw== + dependencies: + "@types/react" "*" + +"@types/react-transition-group@^4.4.5": + version "4.4.5" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.5.tgz#aae20dcf773c5aa275d5b9f7cdbca638abc5e416" + integrity sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^18.0.27": + version "18.0.27" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.27.tgz#d9425abe187a00f8a5ec182b010d4fd9da703b71" + integrity sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/resolve@1.17.1": + version "1.17.1" + resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" + integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw== + dependencies: + "@types/node" "*" + +"@types/retry@0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== + +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + +"@types/semver@^7.3.12": + version "7.3.13" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== + +"@types/serve-index@^1.9.1": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278" + integrity sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg== + dependencies: + "@types/express" "*" + +"@types/serve-static@*", "@types/serve-static@^1.13.10": + version "1.15.0" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.0.tgz#c7930ff61afb334e121a9da780aac0d9b8f34155" + integrity sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg== + dependencies: + "@types/mime" "*" + "@types/node" "*" + +"@types/sockjs@^0.3.33": + version "0.3.33" + resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f" + integrity sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw== + dependencies: + "@types/node" "*" + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/testing-library__jest-dom@^5.9.1": + version "5.14.5" + resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz#d113709c90b3c75fdb127ec338dad7d5f86c974f" + integrity sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ== + dependencies: + "@types/jest" "*" + +"@types/trusted-types@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756" + integrity sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg== + +"@types/ws@^8.5.1": + version "8.5.4" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.4.tgz#bb10e36116d6e570dd943735f86c933c1587b8a5" + integrity sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg== + dependencies: + "@types/node" "*" + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^16.0.0": + version "16.0.5" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.5.tgz#12cc86393985735a283e387936398c2f9e5f88e3" + integrity sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ== + dependencies: + "@types/yargs-parser" "*" + +"@types/yargs@^17.0.8": + version "17.0.20" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.20.tgz#107f0fcc13bd4a524e352b41c49fe88aab5c54d5" + integrity sha512-eknWrTHofQuPk2iuqDm1waA7V6xPlbgBoaaXEgYkClhLOnB0TtbW+srJaOToAgawPxPlHQzwypFA2bhZaUGP5A== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^5.5.0": + version "5.49.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.49.0.tgz#d0b4556f0792194bf0c2fb297897efa321492389" + integrity sha512-IhxabIpcf++TBaBa1h7jtOWyon80SXPRLDq0dVz5SLFC/eW6tofkw/O7Ar3lkx5z5U6wzbKDrl2larprp5kk5Q== + dependencies: + "@typescript-eslint/scope-manager" "5.49.0" + "@typescript-eslint/type-utils" "5.49.0" + "@typescript-eslint/utils" "5.49.0" + debug "^4.3.4" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + regexpp "^3.2.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@^5.0.0": + version "5.49.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.49.0.tgz#7962b4611eb0c8be0e330d6caf4da7f8261c8203" + integrity sha512-veLpCJLYn44Fru7mSvi2doxQMzMCOFSDYdMUQhAzaH1vFYq2RVNpecZ8d18Wh6UMv07yahXkiv/aShWE48iE9Q== + dependencies: + "@typescript-eslint/utils" "5.49.0" + +"@typescript-eslint/parser@^5.5.0": + version "5.49.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.49.0.tgz#d699734b2f20e16351e117417d34a2bc9d7c4b90" + integrity sha512-veDlZN9mUhGqU31Qiv2qEp+XrJj5fgZpJ8PW30sHU+j/8/e5ruAhLaVDAeznS7A7i4ucb/s8IozpDtt9NqCkZg== + dependencies: + "@typescript-eslint/scope-manager" "5.49.0" + "@typescript-eslint/types" "5.49.0" + "@typescript-eslint/typescript-estree" "5.49.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.49.0": + version "5.49.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.49.0.tgz#81b5d899cdae446c26ddf18bd47a2f5484a8af3e" + integrity sha512-clpROBOiMIzpbWNxCe1xDK14uPZh35u4QaZO1GddilEzoCLAEz4szb51rBpdgurs5k2YzPtJeTEN3qVbG+LRUQ== + dependencies: + "@typescript-eslint/types" "5.49.0" + "@typescript-eslint/visitor-keys" "5.49.0" + +"@typescript-eslint/type-utils@5.49.0": + version "5.49.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.49.0.tgz#8d5dcc8d422881e2ccf4ebdc6b1d4cc61aa64125" + integrity sha512-eUgLTYq0tR0FGU5g1YHm4rt5H/+V2IPVkP0cBmbhRyEmyGe4XvJ2YJ6sYTmONfjmdMqyMLad7SB8GvblbeESZA== + dependencies: + "@typescript-eslint/typescript-estree" "5.49.0" + "@typescript-eslint/utils" "5.49.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.49.0": + version "5.49.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.49.0.tgz#ad66766cb36ca1c89fcb6ac8b87ec2e6dac435c3" + integrity sha512-7If46kusG+sSnEpu0yOz2xFv5nRz158nzEXnJFCGVEHWnuzolXKwrH5Bsf9zsNlOQkyZuk0BZKKoJQI+1JPBBg== + +"@typescript-eslint/typescript-estree@5.49.0": + version "5.49.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.49.0.tgz#ebd6294c0ea97891fce6af536048181e23d729c8" + integrity sha512-PBdx+V7deZT/3GjNYPVQv1Nc0U46dAHbIuOG8AZ3on3vuEKiPDwFE/lG1snN2eUB9IhF7EyF7K1hmTcLztNIsA== + dependencies: + "@typescript-eslint/types" "5.49.0" + "@typescript-eslint/visitor-keys" "5.49.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.49.0", "@typescript-eslint/utils@^5.43.0": + version "5.49.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.49.0.tgz#1c07923bc55ff7834dfcde487fff8d8624a87b32" + integrity sha512-cPJue/4Si25FViIb74sHCLtM4nTSBXtLx1d3/QT6mirQ/c65bV8arBEebBJJizfq8W2YyMoPI/WWPFWitmNqnQ== + dependencies: + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.49.0" + "@typescript-eslint/types" "5.49.0" + "@typescript-eslint/typescript-estree" "5.49.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.49.0": + version "5.49.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.49.0.tgz#2561c4da3f235f5c852759bf6c5faec7524f90fe" + integrity sha512-v9jBMjpNWyn8B6k/Mjt6VbUS4J1GvUlR4x3Y+ibnP1z7y7V4n0WRz+50DY6+Myj0UaXVSuUlHohO+eZ8IJEnkg== + dependencies: + "@typescript-eslint/types" "5.49.0" + eslint-visitor-keys "^3.3.0" + +"@webassemblyjs/ast@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + +"@webassemblyjs/floating-point-hex-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" + integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== + +"@webassemblyjs/helper-api-error@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" + integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== + +"@webassemblyjs/helper-buffer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" + integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== + +"@webassemblyjs/helper-numbers@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" + integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" + integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== + +"@webassemblyjs/helper-wasm-section@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" + integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + +"@webassemblyjs/ieee754@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" + integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" + integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" + integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== + +"@webassemblyjs/wasm-edit@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" + integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-wasm-section" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-opt" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wast-printer" "1.11.1" + +"@webassemblyjs/wasm-gen@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" + integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wasm-opt@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" + integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + +"@webassemblyjs/wasm-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" + integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wast-printer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" + integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abab@^2.0.3, abab@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-import-assertions@^1.7.6: + version "1.8.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" + integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-node@^1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" + integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== + dependencies: + acorn "^7.0.0" + acorn-walk "^7.0.0" + xtend "^4.0.2" + +acorn-walk@^7.0.0, acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^7.0.0, acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.2.4, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0: + version "8.8.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +address@^1.0.1, address@^1.1.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e" + integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== + +adjust-sourcemap-loader@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz#fc4a0fd080f7d10471f30a7320f25560ade28c99" + integrity sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A== + dependencies: + loader-utils "^2.0.0" + regex-parser "^2.2.11" + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv-keywords@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.6.0, ajv@^8.8.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1, ansi-escapes@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-html-community@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" + integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +aria-query@^5.0.0, aria-query@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" + integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== + dependencies: + deep-equal "^2.0.5" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +array-flatten@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-includes@^3.1.5, array-includes@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" + integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.flat@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" + integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" + integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + +array.prototype.foreach@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/array.prototype.foreach/-/array.prototype.foreach-1.0.4.tgz#ea248e0bc250fef587c369cc7102908a43d9f23c" + integrity sha512-OYqqGR/56CopyheXNwdlJvFtbSvf2Z9RGvL20X6GvAuKePJ76L/D46BqZn3bITd36QA2Ti7Iy0UwVJaD/YwXZA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-array-method-boxes-properly "^1.0.0" + get-intrinsic "^1.1.3" + is-string "^1.0.7" + +array.prototype.reduce@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz#6b20b0daa9d9734dd6bc7ea66b5bbce395471eac" + integrity sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-array-method-boxes-properly "^1.0.0" + is-string "^1.0.7" + +array.prototype.tosorted@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz#ccf44738aa2b5ac56578ffda97c03fd3e23dd532" + integrity sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.1.3" + +asap@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== + +ast-types-flow@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== + +async@^3.2.3: + version "3.2.4" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +attr-accept@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" + integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== + +autoprefixer@^10.4.13: + version "10.4.13" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.13.tgz#b5136b59930209a321e9fa3dca2e7c4d223e83a8" + integrity sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg== + dependencies: + browserslist "^4.21.4" + caniuse-lite "^1.0.30001426" + fraction.js "^4.2.0" + normalize-range "^0.1.2" + picocolors "^1.0.0" + postcss-value-parser "^4.2.0" + +autosuggest-highlight@^3.1.1: + version "3.3.4" + resolved "https://registry.yarnpkg.com/autosuggest-highlight/-/autosuggest-highlight-3.3.4.tgz#d71b575ba8eab40b5adba73df9244e9ba88cc387" + integrity sha512-j6RETBD2xYnrVcoV1S5R4t3WxOlWZKyDQjkwnggDPSjF5L4jV98ZltBpvPvbkM1HtoSe5o+bNrTHyjPbieGeYA== + dependencies: + remove-accents "^0.4.2" + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +axe-core@^4.6.2: + version "4.6.3" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.6.3.tgz#fc0db6fdb65cc7a80ccf85286d91d64ababa3ece" + integrity sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg== + +axobject-query@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.1.1.tgz#3b6e5c6d4e43ca7ba51c5babf99d22a9c68485e1" + integrity sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg== + dependencies: + deep-equal "^2.0.5" + +babel-jest@^27.4.2, babel-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" + integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== + dependencies: + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-loader@^8.2.3: + version "8.3.0" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.3.0.tgz#124936e841ba4fe8176786d6ff28add1f134d6a8" + integrity sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q== + dependencies: + find-cache-dir "^3.3.1" + loader-utils "^2.0.0" + make-dir "^3.1.0" + schema-utils "^2.6.5" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" + integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-macros@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" + integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== + dependencies: + "@babel/runtime" "^7.12.5" + cosmiconfig "^7.0.0" + resolve "^1.19.0" + +babel-plugin-named-asset-import@^0.3.8: + version "0.3.8" + resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz#6b7fa43c59229685368683c28bc9734f24524cc2" + integrity sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q== + +babel-plugin-polyfill-corejs2@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz#5d1bd3836d0a19e1b84bbf2d9640ccb6f951c122" + integrity sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q== + dependencies: + "@babel/compat-data" "^7.17.7" + "@babel/helper-define-polyfill-provider" "^0.3.3" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz#56ad88237137eade485a71b52f72dbed57c6230a" + integrity sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.3" + core-js-compat "^3.25.1" + +babel-plugin-polyfill-regenerator@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz#390f91c38d90473592ed43351e801a9d3e0fd747" + integrity sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.3" + +babel-plugin-transform-react-remove-prop-types@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a" + integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA== + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" + integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag== + dependencies: + babel-plugin-jest-hoist "^27.5.1" + babel-preset-current-node-syntax "^1.0.0" + +babel-preset-react-app@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz#ed6005a20a24f2c88521809fa9aea99903751584" + integrity sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg== + dependencies: + "@babel/core" "^7.16.0" + "@babel/plugin-proposal-class-properties" "^7.16.0" + "@babel/plugin-proposal-decorators" "^7.16.4" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.0" + "@babel/plugin-proposal-numeric-separator" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.0" + "@babel/plugin-proposal-private-methods" "^7.16.0" + "@babel/plugin-transform-flow-strip-types" "^7.16.0" + "@babel/plugin-transform-react-display-name" "^7.16.0" + "@babel/plugin-transform-runtime" "^7.16.4" + "@babel/preset-env" "^7.16.4" + "@babel/preset-react" "^7.16.0" + "@babel/preset-typescript" "^7.16.0" + "@babel/runtime" "^7.16.3" + babel-plugin-macros "^3.1.0" + babel-plugin-transform-react-remove-prop-types "^0.4.24" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== + +bfj@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/bfj/-/bfj-7.0.2.tgz#1988ce76f3add9ac2913fd8ba47aad9e651bfbb2" + integrity sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw== + dependencies: + bluebird "^3.5.5" + check-types "^11.1.1" + hoopy "^0.1.4" + tryer "^1.0.1" + +big-integer@^1.6.16: + version "1.6.51" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" + integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bluebird@^3.5.5: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +body-parser@1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" + +bonjour-service@^1.0.11: + version "1.1.0" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.1.0.tgz#424170268d68af26ff83a5c640b95def01803a13" + integrity sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q== + dependencies: + array-flatten "^2.1.2" + dns-equal "^1.0.0" + fast-deep-equal "^3.1.3" + multicast-dns "^7.2.5" + +boolbase@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +broadcast-channel@^3.4.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937" + integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg== + dependencies: + "@babel/runtime" "^7.7.2" + detect-node "^2.1.0" + js-sha3 "0.8.0" + microseconds "0.2.0" + nano-time "1.0.0" + oblivious-set "1.0.0" + rimraf "3.0.2" + unload "2.2.0" + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.18.1, browserslist@^4.21.3, browserslist@^4.21.4: + version "4.21.5" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7" + integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== + dependencies: + caniuse-lite "^1.0.30001449" + electron-to-chromium "^1.4.284" + node-releases "^2.0.8" + update-browserslist-db "^1.0.10" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +builtin-modules@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + +camelcase-css@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0, camelcase@^6.2.1: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001426, caniuse-lite@^1.0.30001449: + version "1.0.30001449" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001449.tgz#a8d11f6a814c75c9ce9d851dc53eb1d1dfbcd657" + integrity sha512-CPB+UL9XMT/Av+pJxCKGhdx+yg1hzplvFJQlJ2n68PyQGMz9L/E2zCyLdOL8uasbouTUgnPl+y0tccI/se+BEw== + +case-sensitive-paths-webpack-plugin@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4" + integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw== + +chalk@^2.0.0, chalk@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +char-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-2.0.1.tgz#6dafdb25f9d3349914079f010ba8d0e6ff9cd01e" + integrity sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw== + +check-types@^11.1.1: + version "11.2.2" + resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.2.2.tgz#7afc0b6a860d686885062f2dba888ba5710335b4" + integrity sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA== + +chokidar@^3.4.2, chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +ci-info@^3.2.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.7.1.tgz#708a6cdae38915d597afdf3b145f2f8e1ff55f3f" + integrity sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w== + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + +clean-css@^5.2.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.2.tgz#70ecc7d4d4114921f5d298349ff86a31a9975224" + integrity sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww== + dependencies: + source-map "~0.6.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clsx@^1.1.1, clsx@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" + integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +coa@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" + integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== + dependencies: + "@types/q" "^1.5.1" + chalk "^2.4.1" + q "^1.1.2" + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@^1.1.4, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colord@^2.9.1: + version "2.9.3" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" + integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== + +colorette@^2.0.10: + version "2.0.19" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" + integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +commander@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +commander@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + +common-path-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0" + integrity sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w== + +common-tags@^1.8.0: + version "1.8.2" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" + integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +confusing-browser-globals@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" + integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== + +connect-history-api-fallback@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" + integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + +core-js-compat@^3.25.1: + version "3.27.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.27.2.tgz#607c50ad6db8fd8326af0b2883ebb987be3786da" + integrity sha512-welaYuF7ZtbYKGrIy7y3eb40d37rG1FvzEOfe7hSLd2iD6duMDqUhRfSvCGyC46HhR6Y8JXXdZ2lnRUMkPBpvg== + dependencies: + browserslist "^4.21.4" + +core-js-pure@^3.23.3: + version "3.27.2" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.27.2.tgz#47e9cc96c639eefc910da03c3ece26c5067c7553" + integrity sha512-Cf2jqAbXgWH3VVzjyaaFkY1EBazxugUepGymDoeteyYr9ByX51kD2jdHZlsEF/xnJMyN3Prua7mQuzwMg6Zc9A== + +core-js@^3.19.2: + version "3.27.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.27.2.tgz#85b35453a424abdcacb97474797815f4d62ebbf7" + integrity sha512-9ashVQskuh5AZEZ1JdQWp1GqSoC1e1G87MzRqg2gIfVAQ7Qn9K+uFj8EcniUFA4P2NLZfV+TOlX1SzoKfo+s7w== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + 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" + +cosmiconfig@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" + integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + +css-blank-pseudo@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz#36523b01c12a25d812df343a32c322d2a2324561" + integrity sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ== + dependencies: + postcss-selector-parser "^6.0.9" + +css-declaration-sorter@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz#be5e1d71b7a992433fb1c542c7a1b835e45682ec" + integrity sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w== + +css-has-pseudo@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz#57f6be91ca242d5c9020ee3e51bbb5b89fc7af73" + integrity sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw== + dependencies: + postcss-selector-parser "^6.0.9" + +css-loader@^6.5.1: + version "6.7.3" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.3.tgz#1e8799f3ccc5874fdd55461af51137fcc5befbcd" + integrity sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ== + dependencies: + icss-utils "^5.1.0" + postcss "^8.4.19" + postcss-modules-extract-imports "^3.0.0" + postcss-modules-local-by-default "^4.0.0" + postcss-modules-scope "^3.0.0" + postcss-modules-values "^4.0.0" + postcss-value-parser "^4.2.0" + semver "^7.3.8" + +css-mediaquery@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0" + integrity sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q== + +css-minimizer-webpack-plugin@^3.2.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz#ab78f781ced9181992fe7b6e4f3422e76429878f" + integrity sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q== + dependencies: + cssnano "^5.0.6" + jest-worker "^27.0.2" + postcss "^8.3.5" + schema-utils "^4.0.0" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + +css-prefers-color-scheme@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz#ca8a22e5992c10a5b9d315155e7caee625903349" + integrity sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA== + +css-select-base-adapter@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" + integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== + +css-select@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" + integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== + dependencies: + boolbase "^1.0.0" + css-what "^3.2.1" + domutils "^1.7.0" + nth-check "^1.0.2" + +css-select@^4.1.3: + version "4.3.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" + integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== + dependencies: + boolbase "^1.0.0" + css-what "^6.0.1" + domhandler "^4.3.1" + domutils "^2.8.0" + nth-check "^2.0.1" + +css-tree@1.0.0-alpha.37: + version "1.0.0-alpha.37" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" + integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== + dependencies: + mdn-data "2.0.4" + source-map "^0.6.1" + +css-tree@^1.1.2, css-tree@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +css-what@^3.2.1: + version "3.4.2" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" + integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== + +css-what@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== + +css.escape@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" + integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== + +cssdb@^7.1.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-7.4.1.tgz#61d55c0173126689922a219e15e131e4b5caf422" + integrity sha512-0Q8NOMpXJ3iTDDbUv9grcmQAfdDx4qz+fN/+Md2FGbevT+6+bJNQ2LjB2YIUlLbpBTM32idU1Sb+tb/uGt6/XQ== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-default@^5.2.13: + version "5.2.13" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.13.tgz#e7353b0c57975d1bdd97ac96e68e5c1b8c68e990" + integrity sha512-PX7sQ4Pb+UtOWuz8A1d+Rbi+WimBIxJTRyBdgGp1J75VU0r/HFQeLnMYgHiCAp6AR4rqrc7Y4R+1Rjk3KJz6DQ== + dependencies: + css-declaration-sorter "^6.3.1" + cssnano-utils "^3.1.0" + postcss-calc "^8.2.3" + postcss-colormin "^5.3.0" + postcss-convert-values "^5.1.3" + postcss-discard-comments "^5.1.2" + postcss-discard-duplicates "^5.1.0" + postcss-discard-empty "^5.1.1" + postcss-discard-overridden "^5.1.0" + postcss-merge-longhand "^5.1.7" + postcss-merge-rules "^5.1.3" + postcss-minify-font-values "^5.1.0" + postcss-minify-gradients "^5.1.1" + postcss-minify-params "^5.1.4" + postcss-minify-selectors "^5.2.1" + postcss-normalize-charset "^5.1.0" + postcss-normalize-display-values "^5.1.0" + postcss-normalize-positions "^5.1.1" + postcss-normalize-repeat-style "^5.1.1" + postcss-normalize-string "^5.1.0" + postcss-normalize-timing-functions "^5.1.0" + postcss-normalize-unicode "^5.1.1" + postcss-normalize-url "^5.1.0" + postcss-normalize-whitespace "^5.1.1" + postcss-ordered-values "^5.1.3" + postcss-reduce-initial "^5.1.1" + postcss-reduce-transforms "^5.1.0" + postcss-svgo "^5.1.0" + postcss-unique-selectors "^5.1.1" + +cssnano-utils@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861" + integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA== + +cssnano@^5.0.6: + version "5.1.14" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.14.tgz#07b0af6da73641276fe5a6d45757702ebae2eb05" + integrity sha512-Oou7ihiTocbKqi0J1bB+TRJIQX5RMR3JghA8hcWSw9mjBLQ5Y3RWqEDoYG3sRNlAbCIXpqMoZGbq5KDR3vdzgw== + dependencies: + cssnano-preset-default "^5.2.13" + lilconfig "^2.0.3" + yaml "^1.10.2" + +csso@^4.0.2, csso@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== + dependencies: + css-tree "^1.1.2" + +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +csstype@^3.0.2, csstype@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" + integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== + +damerau-levenshtein@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== + +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +date-fns@^2.19.0: + version "2.29.3" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" + integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== + +debug@2.6.9, debug@^2.6.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +decimal.js@^10.2.1: + version "10.4.3" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" + integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== + +decode-uri-component@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== + +deep-equal@^2.0.5: + version "2.2.0" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.0.tgz#5caeace9c781028b9ff459f33b779346637c43e6" + integrity sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw== + dependencies: + call-bind "^1.0.2" + es-get-iterator "^1.1.2" + get-intrinsic "^1.1.3" + is-arguments "^1.1.1" + is-array-buffer "^3.0.1" + is-date-object "^1.0.5" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + isarray "^2.0.5" + object-is "^1.1.5" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + side-channel "^1.0.4" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.9" + +deep-is@^0.1.3, deep-is@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.3.0" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.0.tgz#65491893ec47756d44719ae520e0e2609233b59b" + integrity sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og== + +default-gateway@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" + integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== + dependencies: + execa "^5.0.0" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + +define-properties@^1.1.3, define-properties@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" + integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +defined@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" + integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +detect-node@^2.0.4, detect-node@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +detect-port-alt@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" + integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q== + dependencies: + address "^1.0.1" + debug "^2.6.0" + +detective@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034" + integrity sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw== + dependencies: + acorn-node "^1.8.2" + defined "^1.0.0" + minimist "^1.2.6" + +didyoumean@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" + integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== + +diff-sequences@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" + integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== + +diff-sequences@^29.3.1: + version "29.3.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.3.1.tgz#104b5b95fe725932421a9c6e5b4bef84c3f2249e" + integrity sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dlv@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== + +dns-packet@^5.2.2: + version "5.4.0" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.4.0.tgz#1f88477cf9f27e78a213fb6d118ae38e759a879b" + integrity sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g== + dependencies: + "@leichtgewicht/ip-codec" "^2.0.1" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-accessibility-api@^0.5.6, dom-accessibility-api@^0.5.9: + version "0.5.16" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453" + integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg== + +dom-converter@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" + integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== + dependencies: + utila "~0.4" + +dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +dom-serializer@^1.0.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" + integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +domelementtype@1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1, domelementtype@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== + dependencies: + domelementtype "^2.2.0" + +domutils@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^2.5.2, domutils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +dotenv-expand@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" + integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== + +dotenv@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + +duplex-maker@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/duplex-maker/-/duplex-maker-1.0.0.tgz#1604f8b943cb0063a6d3e1fe42aa65113a79da4a" + integrity sha512-KoHuzggxg7f+vvjqOHfXxaQYI1POzBm+ah0eec7YDssZmbt6QFBI8d1nl5GQwAgR2f+VQCPvyvZtmWWqWuFtlA== + +duplexer@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +duplexify@^3.5.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +ejs@^3.1.6: + version "3.1.8" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.8.tgz#758d32910c78047585c7ef1f92f9ee041c1c190b" + integrity sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ== + dependencies: + jake "^10.8.5" + +electron-to-chromium@^1.4.284: + version "1.4.284" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592" + integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA== + +emittery@^0.10.2: + version "0.10.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" + integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== + +emittery@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" + integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +end-of-stream@^1.0.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^5.10.0: + version "5.12.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz#300e1c90228f5b570c4d35babf263f6da7155634" + integrity sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +env-cmd@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/env-cmd/-/env-cmd-10.1.0.tgz#c7f5d3b550c9519f137fdac4dd8fb6866a8c8c4b" + integrity sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA== + dependencies: + commander "^4.0.0" + cross-spawn "^7.0.0" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +error-stack-parser@^2.0.6: + version "2.1.4" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286" + integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ== + dependencies: + stackframe "^1.3.4" + +es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.20.4: + version "1.21.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.1.tgz#e6105a099967c08377830a0c9cb589d570dd86c6" + integrity sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.1.3" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.4" + is-array-buffer "^3.0.1" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.10" + is-weakref "^1.0.2" + object-inspect "^1.12.2" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + safe-regex-test "^1.0.0" + string.prototype.trimend "^1.0.6" + string.prototype.trimstart "^1.0.6" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.9" + +es-array-method-boxes-properly@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" + integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== + +es-get-iterator@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.7" + isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" + +es-module-lexer@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== + +es-set-tostringtag@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" + integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + dependencies: + get-intrinsic "^1.1.3" + has "^1.0.3" + has-tostringtag "^1.0.0" + +es-shim-unscopables@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" + integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + dependencies: + has "^1.0.3" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-config-prettier@^8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz#dec1d29ab728f4fa63061774e1672ac4e363d207" + integrity sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA== + +eslint-config-react-app@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz#73ba3929978001c5c86274c017ea57eb5fa644b4" + integrity sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA== + dependencies: + "@babel/core" "^7.16.0" + "@babel/eslint-parser" "^7.16.3" + "@rushstack/eslint-patch" "^1.1.0" + "@typescript-eslint/eslint-plugin" "^5.5.0" + "@typescript-eslint/parser" "^5.5.0" + babel-preset-react-app "^10.0.1" + confusing-browser-globals "^1.0.11" + eslint-plugin-flowtype "^8.0.3" + eslint-plugin-import "^2.25.3" + eslint-plugin-jest "^25.3.0" + eslint-plugin-jsx-a11y "^6.5.1" + eslint-plugin-react "^7.27.1" + eslint-plugin-react-hooks "^4.3.0" + eslint-plugin-testing-library "^5.0.1" + +eslint-import-resolver-node@^0.3.7: + version "0.3.7" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7" + integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== + dependencies: + debug "^3.2.7" + is-core-module "^2.11.0" + resolve "^1.22.1" + +eslint-module-utils@^2.7.4: + version "2.7.4" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974" + integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== + dependencies: + debug "^3.2.7" + +eslint-plugin-flowtype@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz#e1557e37118f24734aa3122e7536a038d34a4912" + integrity sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ== + dependencies: + lodash "^4.17.21" + string-natural-compare "^3.0.1" + +eslint-plugin-import@^2.25.3: + version "2.27.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz#876a6d03f52608a3e5bb439c2550588e51dd6c65" + integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow== + dependencies: + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + array.prototype.flatmap "^1.3.1" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.7" + eslint-module-utils "^2.7.4" + has "^1.0.3" + is-core-module "^2.11.0" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.values "^1.1.6" + resolve "^1.22.1" + semver "^6.3.0" + tsconfig-paths "^3.14.1" + +eslint-plugin-jest@^25.3.0: + version "25.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz#ff4ac97520b53a96187bad9c9814e7d00de09a6a" + integrity sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ== + dependencies: + "@typescript-eslint/experimental-utils" "^5.0.0" + +eslint-plugin-jsx-a11y@^6.5.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz#fca5e02d115f48c9a597a6894d5bcec2f7a76976" + integrity sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA== + dependencies: + "@babel/runtime" "^7.20.7" + aria-query "^5.1.3" + array-includes "^3.1.6" + array.prototype.flatmap "^1.3.1" + ast-types-flow "^0.0.7" + axe-core "^4.6.2" + axobject-query "^3.1.1" + damerau-levenshtein "^1.0.8" + emoji-regex "^9.2.2" + has "^1.0.3" + jsx-ast-utils "^3.3.3" + language-tags "=1.0.5" + minimatch "^3.1.2" + object.entries "^1.1.6" + object.fromentries "^2.0.6" + semver "^6.3.0" + +eslint-plugin-prettier@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" + integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== + dependencies: + prettier-linter-helpers "^1.0.0" + +eslint-plugin-react-hooks@^4.3.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== + +eslint-plugin-react@^7.27.1: + version "7.32.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz#e71f21c7c265ebce01bcbc9d0955170c55571f10" + integrity sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg== + dependencies: + array-includes "^3.1.6" + array.prototype.flatmap "^1.3.1" + array.prototype.tosorted "^1.1.1" + 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.6" + object.fromentries "^2.0.6" + object.hasown "^1.1.2" + object.values "^1.1.6" + prop-types "^15.8.1" + resolve "^2.0.0-next.4" + semver "^6.3.0" + string.prototype.matchall "^4.0.8" + +eslint-plugin-testing-library@^5.0.1: + version "5.10.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.10.0.tgz#7fc5fec639ae7f84f434562560cf26cfc0ab329d" + integrity sha512-aTOsCAEI9trrX3TLOnsskfhe57DmsjP/yMKLPqg4ftdRvfR4qut2PGWUa8TwP7whZbwMzJjh98tgAPcE8vdHow== + dependencies: + "@typescript-eslint/utils" "^5.43.0" + +eslint-scope@5.1.1, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint-webpack-plugin@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz#1978cdb9edc461e4b0195a20da950cf57988347c" + integrity sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w== + dependencies: + "@types/eslint" "^7.29.0 || ^8.4.1" + jest-worker "^28.0.2" + micromatch "^4.0.5" + normalize-path "^3.0.0" + schema-utils "^4.0.0" + +eslint@^8.3.0, eslint@^8.33.0: + version "8.33.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.33.0.tgz#02f110f32998cb598c6461f24f4d306e41ca33d7" + integrity sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA== + dependencies: + "@eslint/eslintrc" "^1.4.1" + "@humanwhocodes/config-array" "^0.11.8" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + 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.4.0" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-sdsl "^4.1.4" + 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" + +espree@^9.4.0: + version "9.4.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" + integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== + dependencies: + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-walker@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" + integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eventemitter3@^4.0.0, eventemitter3@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" + integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== + dependencies: + "@jest/types" "^27.5.1" + jest-get-type "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + +expect@^29.0.0: + version "29.4.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.4.1.tgz#58cfeea9cbf479b64ed081fd1e074ac8beb5a1fe" + integrity sha512-OKrGESHOaMxK3b6zxIq9SOW8kEXztKff/Dvg88j4xIJxur1hspEbedVkR3GpHe5LO+WB2Qw7OWN0RMTdp6as5A== + dependencies: + "@jest/expect-utils" "^29.4.1" + jest-get-type "^29.2.0" + jest-matcher-utils "^29.4.1" + jest-message-util "^29.4.1" + jest-util "^29.4.1" + +express@^4.17.3: + version "4.18.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" + integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.5.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-glob@^3.2.12, fast-glob@^3.2.9: + version "3.2.12" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-loader@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" + integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + +file-selector@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.5.0.tgz#21c7126dc9728b31a2742d91cab20d55e67e4fb4" + integrity sha512-s8KNnmIDTBoD0p9uJ9uD0XY38SCeBOtj0UMXyQSLg1Ypfrfj8+dAvwsLjYQkQ2GjhVtp2HrnF5cJzMhBjfD8HA== + dependencies: + tslib "^2.0.3" + +filelist@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" + integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== + dependencies: + minimatch "^5.0.1" + +filesize@^8.0.6: + version "8.0.7" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8" + integrity sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +filter-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" + integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ== + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-cache-dir@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +follow-redirects@^1.0.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +fork-ts-checker-webpack-plugin@^6.5.0: + version "6.5.2" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz#4f67183f2f9eb8ba7df7177ce3cf3e75cdafb340" + integrity sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA== + dependencies: + "@babel/code-frame" "^7.8.3" + "@types/json-schema" "^7.0.5" + chalk "^4.1.0" + chokidar "^3.4.2" + cosmiconfig "^6.0.0" + deepmerge "^4.2.2" + fs-extra "^9.0.0" + glob "^7.1.6" + memfs "^3.1.2" + minimatch "^3.0.4" + schema-utils "2.7.0" + semver "^7.3.2" + tapable "^1.0.0" + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fraction.js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" + integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs-extra@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^9.0.0, fs-extra@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-monkey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" + integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + +functions-have-names@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" + integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +get-own-enumerable-property-symbols@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" + integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + +globby@^11.0.4, globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + +gzip-size@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" + integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== + dependencies: + duplexer "^0.1.2" + +gzipper@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/gzipper/-/gzipper-7.2.0.tgz#da8c6069d66fa2a927594cc035ee144ecb853005" + integrity sha512-qwYQr7GWBXIm9Cdzud+tyM/s9N+QFzGDZoF9YR8RYJbDKOYowzjMDPEinFtm78EQeeYMC/FJW2FXY0bHkyUgsA== + dependencies: + "@gfx/zopfli" "^1.0.15" + commander "^7.2.0" + deep-equal "^2.0.5" + simple-zstd "^1.4.0" + uuid "^8.3.2" + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +harmony-reflect@^1.4.6: + version "1.6.2" + resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.2.tgz#31ecbd32e648a34d030d86adb67d4d47547fe710" + integrity sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g== + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +history@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b" + integrity sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ== + dependencies: + "@babel/runtime" "^7.7.6" + +hoist-non-react-statics@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +hoopy@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" + integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ== + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + +html-entities@^2.1.0, html-entities@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" + integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +html-minifier-terser@^6.0.2: + version "6.1.0" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab" + integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw== + dependencies: + camel-case "^4.1.2" + clean-css "^5.2.2" + commander "^8.3.0" + he "^1.2.0" + param-case "^3.0.4" + relateurl "^0.2.7" + terser "^5.10.0" + +html-webpack-plugin@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz#c3911936f57681c1f9f4d8b68c158cd9dfe52f50" + integrity sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw== + dependencies: + "@types/html-minifier-terser" "^6.0.0" + html-minifier-terser "^6.0.2" + lodash "^4.17.21" + pretty-error "^4.0.0" + tapable "^2.0.0" + +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.5.1: + version "0.5.8" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== + +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +http-proxy-middleware@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f" + integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw== + dependencies: + "@types/http-proxy" "^1.17.8" + http-proxy "^1.18.1" + is-glob "^4.0.1" + is-plain-obj "^3.0.0" + micromatch "^4.0.2" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +icss-utils@^5.0.0, icss-utils@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== + +idb@^7.0.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" + integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ== + +identity-obj-proxy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz#94d2bda96084453ef36fbc5aaec37e0f79f1fc14" + integrity sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA== + dependencies: + harmony-reflect "^1.4.6" + +ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +immer@^9.0.7: + version "9.0.19" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.19.tgz#67fb97310555690b5f9cd8380d38fc0aabb6b38b" + integrity sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ== + +import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflection@~1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" + integrity sha512-lRy4DxuIFWXlJU7ed8UiTJOSTqStqYdEb4CEbtXfNbkdj3nH1L+reUWiE10VWcJS2yR7tge8Z74pJjtBjNwj0w== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + +ini@^1.3.5: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +internal-slot@^1.0.3, internal-slot@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.4.tgz#8551e7baf74a7a6ba5f749cfb16aa60722f0d6f3" + integrity sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ== + dependencies: + get-intrinsic "^1.1.3" + has "^1.0.3" + side-channel "^1.0.4" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +ipaddr.js@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" + integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + +is-arguments@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-array-buffer@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.1.tgz#deb1db4fcae48308d54ef2442706c0393997052a" + integrity sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-typed-array "^1.1.10" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.11.0, is-core-module@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" + integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1, is-date-object@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-map@^2.0.1, is-map@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" + integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + +is-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" + integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" + integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== + +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + integrity sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA== + +is-root@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" + integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== + +is-set@^2.0.1, is-set@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" + integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10, is-typed-array@^1.1.9: + version "1.1.10" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" + integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + +is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-weakset@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" + integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +is-zst@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-zst/-/is-zst-1.0.0.tgz#97462bb1a376dabba561e249ea754801e9b90fe0" + integrity sha512-ZA5lvshKAl8z30dX7saXLpVhpsq3d2EHK9uf7qtUjnOtdw4XBpAoWb2RvZ5kyoaebdoidnGI0g2hn9Z7ObPbww== + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jake@^10.8.5: + version "10.8.5" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.5.tgz#f2183d2c59382cb274226034543b9c03b8164c46" + integrity sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw== + dependencies: + async "^3.2.3" + chalk "^4.0.2" + filelist "^1.0.1" + minimatch "^3.0.4" + +jest-changed-files@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" + integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== + dependencies: + "@jest/types" "^27.5.1" + execa "^5.0.0" + throat "^6.0.1" + +jest-circus@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc" + integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^27.5.1" + is-generator-fn "^2.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" + +jest-cli@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" + integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== + dependencies: + "@jest/core" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + prompts "^2.0.1" + yargs "^16.2.0" + +jest-config@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" + integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== + dependencies: + "@babel/core" "^7.8.0" + "@jest/test-sequencer" "^27.5.1" + "@jest/types" "^27.5.1" + babel-jest "^27.5.1" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.9" + jest-circus "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-get-type "^27.5.1" + jest-jasmine2 "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runner "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^27.5.1" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" + integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-diff@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.4.1.tgz#9a6dc715037e1fa7a8a44554e7d272088c4029bd" + integrity sha512-uazdl2g331iY56CEyfbNA0Ut7Mn2ulAG5vUaEHXycf1L6IPyuImIxSz4F0VYBKi7LYIuxOwTZzK3wh5jHzASMw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.3.1" + jest-get-type "^29.2.0" + pretty-format "^29.4.1" + +jest-docblock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" + integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== + dependencies: + detect-newline "^3.0.0" + +jest-each@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" + integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + jest-get-type "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + +jest-environment-jsdom@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" + integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + jsdom "^16.6.0" + +jest-environment-node@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" + integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + +jest-get-type@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" + integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== + +jest-get-type@^29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.2.0.tgz#726646f927ef61d583a3b3adb1ab13f3a5036408" + integrity sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA== + +jest-haste-map@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" + integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== + dependencies: + "@jest/types" "^27.5.1" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^27.5.1" + jest-serializer "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + +jest-jasmine2@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" + integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^27.5.1" + is-generator-fn "^2.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + throat "^6.0.1" + +jest-leak-detector@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" + integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== + dependencies: + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" + integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== + dependencies: + chalk "^4.0.0" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-matcher-utils@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.4.1.tgz#73d834e305909c3b43285fbc76f78bf0ad7e1954" + integrity sha512-k5h0u8V4nAEy6lSACepxL/rw78FLDkBnXhZVgFneVpnJONhb2DhZj/Gv4eNe+1XqQ5IhgUcqj745UwH0HJmMnA== + dependencies: + chalk "^4.0.0" + jest-diff "^29.4.1" + jest-get-type "^29.2.0" + pretty-format "^29.4.1" + +jest-message-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" + integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.5.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-message-util@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.3.tgz#232def7f2e333f1eecc90649b5b94b0055e7c43d" + integrity sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^28.1.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^28.1.3" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-message-util@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.4.1.tgz#522623aa1df9a36ebfdffb06495c7d9d19e8a845" + integrity sha512-H4/I0cXUaLeCw6FM+i4AwCnOwHRgitdaUFOdm49022YD5nfyr8C/DrbXOBEyJaj+w/y0gGJ57klssOaUiLLQGQ== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.4.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.4.1" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" + integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" + integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== + +jest-regex-util@^28.0.0: + version "28.0.2" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead" + integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== + +jest-resolve-dependencies@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" + integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== + dependencies: + "@jest/types" "^27.5.1" + jest-regex-util "^27.5.1" + jest-snapshot "^27.5.1" + +jest-resolve@^27.4.2, jest-resolve@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" + integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-pnp-resolver "^1.2.2" + jest-util "^27.5.1" + jest-validate "^27.5.1" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" + integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.8.1" + graceful-fs "^4.2.9" + jest-docblock "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-haste-map "^27.5.1" + jest-leak-detector "^27.5.1" + jest-message-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runtime "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + source-map-support "^0.5.6" + throat "^6.0.1" + +jest-runtime@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" + integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/globals" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-serializer@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" + integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.9" + +jest-snapshot@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" + integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.0.0" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.5.1" + graceful-fs "^4.2.9" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + jest-haste-map "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + natural-compare "^1.4.0" + pretty-format "^27.5.1" + semver "^7.3.2" + +jest-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" + integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-util@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.3.tgz#f4f932aa0074f0679943220ff9cbba7e497028b0" + integrity sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-util@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.4.1.tgz#2eeed98ff4563b441b5a656ed1a786e3abc3e4c4" + integrity sha512-bQy9FPGxVutgpN4VRc0hk6w7Hx/m6L53QxpDreTZgJd9gfx/AV2MjyPde9tGyZRINAUrSv57p2inGBu2dRLmkQ== + dependencies: + "@jest/types" "^29.4.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" + integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== + dependencies: + "@jest/types" "^27.5.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^27.5.1" + leven "^3.1.0" + pretty-format "^27.5.1" + +jest-watch-typeahead@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/jest-watch-typeahead/-/jest-watch-typeahead-1.1.0.tgz#b4a6826dfb9c9420da2f7bc900de59dad11266a9" + integrity sha512-Va5nLSJTN7YFtC2jd+7wsoe1pNe5K4ShLux/E5iHEwlB9AxaxmggY7to9KUqKojhaJw3aXqt5WAb4jGPOolpEw== + dependencies: + ansi-escapes "^4.3.1" + chalk "^4.0.0" + jest-regex-util "^28.0.0" + jest-watcher "^28.0.0" + slash "^4.0.0" + string-length "^5.0.1" + strip-ansi "^7.0.1" + +jest-watcher@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" + integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== + dependencies: + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^27.5.1" + string-length "^4.0.1" + +jest-watcher@^28.0.0: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-28.1.3.tgz#c6023a59ba2255e3b4c57179fc94164b3e73abd4" + integrity sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g== + dependencies: + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.10.2" + jest-util "^28.1.3" + string-length "^4.0.1" + +jest-worker@^26.2.1: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^7.0.0" + +jest-worker@^27.0.2, jest-worker@^27.4.5, jest-worker@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest-worker@^28.0.2: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.3.tgz#7e3c4ce3fa23d1bb6accb169e7f396f98ed4bb98" + integrity sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^27.4.3: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" + integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== + dependencies: + "@jest/core" "^27.5.1" + import-local "^3.0.2" + jest-cli "^27.5.1" + +js-sdsl@^4.1.4: + version "4.3.0" + resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711" + integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ== + +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + +json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-schema@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2, json5@^2.2.0, json5@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonexport@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsonexport/-/jsonexport-3.2.0.tgz#e5b4905ea1f6c8f8e0f62e4ceb26e4a31f1c93a8" + integrity sha512-GbO9ugb0YTZatPd/hqCGR0FSwbr82H6OzG04yzdrG7XOe4QZ0jhQ+kOsB29zqkzoYJLmLxbbrFiuwbQu891XnQ== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonpointer@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559" + integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ== + +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea" + integrity sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw== + dependencies: + array-includes "^3.1.5" + object.assign "^4.1.3" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +klona@^2.0.4, klona@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" + integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== + +language-subtag-registry@~0.3.2: + version "0.3.22" + resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" + integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== + +language-tags@=1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" + integrity sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ== + dependencies: + language-subtag-registry "~0.3.2" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lilconfig@^2.0.3, lilconfig@^2.0.5, lilconfig@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" + integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +loader-utils@^2.0.0, loader-utils@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" + integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +loader-utils@^3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.2.1.tgz#4fb104b599daafd82ef3e1a41fb9265f87e1f576" + integrity sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw== + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== + +lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0, lodash@~4.17.5: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +lz-string@^1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" + integrity sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ== + +magic-string@^0.25.0, magic-string@^0.25.7: + version "0.25.9" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" + integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== + dependencies: + sourcemap-codec "^1.4.8" + +make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +match-sorter@^6.0.2: + version "6.3.1" + resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda" + integrity sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw== + dependencies: + "@babel/runtime" "^7.12.5" + remove-accents "0.4.2" + +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== + +mdn-data@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" + integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +memfs@^3.1.2, memfs@^3.4.3: + version "3.4.13" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.13.tgz#248a8bd239b3c240175cd5ec548de5227fc4f345" + integrity sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg== + dependencies: + fs-monkey "^1.0.3" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +microseconds@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39" + integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA== + +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +mini-css-extract-plugin@^2.4.5: + version "2.7.2" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz#e049d3ea7d3e4e773aad585c6cb329ce0c7b72d7" + integrity sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw== + dependencies: + schema-utils "^4.0.0" + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" + integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== + +mkdirp@~0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns@^7.2.5: + version "7.2.5" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" + integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg== + dependencies: + dns-packet "^5.2.2" + thunky "^1.0.2" + +nano-time@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef" + integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA== + dependencies: + big-integer "^1.6.16" + +nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-forge@^1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-polyglot@^2.2.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/node-polyglot/-/node-polyglot-2.5.0.tgz#bd2703f5c5e784c3917abeaa4b5d4604a4722d7e" + integrity sha512-zXVwHNhFsG3mls+LKHxoHF70GQOL3FTDT3jH7ldkb95kG76RdU7F/NbvxV7D2hNIL9VpWXW6y78Fz+3KZkatRg== + dependencies: + array.prototype.foreach "^1.0.2" + has "^1.0.3" + object.entries "^1.1.5" + string.prototype.trim "^1.2.6" + warning "^4.0.3" + +node-releases@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.8.tgz#0f349cdc8fcfa39a92ac0be9bc48b7706292b9ae" + integrity sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== + +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nth-check@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + +nwsapi@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.2.tgz#e5418863e7905df67d51ec95938d67bf801f0bb0" + integrity sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw== + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== + +object-inspect@^1.12.2, object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +object-is@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.3, object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.entries@^1.1.5, object.entries@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.6.tgz#9737d0e5b8291edd340a3e3264bb8a3b00d5fa23" + integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +object.fromentries@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" + integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +object.getownpropertydescriptors@^2.1.0: + version "2.1.5" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.5.tgz#db5a9002489b64eef903df81d6623c07e5b4b4d3" + integrity sha512-yDNzckpM6ntyQiGTik1fKV1DcVDRS+w8bvpWNCBanvH5LfRX9O8WTHqQzG4RZwRAM4I0oU7TV11Lj5v0g20ibw== + dependencies: + array.prototype.reduce "^1.0.5" + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +object.hasown@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92" + integrity sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw== + dependencies: + define-properties "^1.1.4" + es-abstract "^1.20.4" + +object.values@^1.1.0, object.values@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" + integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +oblivious-set@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566" + integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw== + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^8.0.9, open@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" + integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +os-tmpdir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-retry@^4.5.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" + integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== + dependencies: + "@types/retry" "0.12.0" + retry "^0.13.1" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +param-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0, parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse5@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +peek-stream@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/peek-stream/-/peek-stream-1.1.3.tgz#3b35d84b7ccbbd262fff31dc10da56856ead6d67" + integrity sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA== + dependencies: + buffer-from "^1.0.0" + duplexify "^3.5.0" + through2 "^2.0.3" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== + +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pirates@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + +pkg-dir@^4.1.0, pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-up@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + +postcss-attribute-case-insensitive@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz#03d761b24afc04c09e757e92ff53716ae8ea2741" + integrity sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ== + dependencies: + postcss-selector-parser "^6.0.10" + +postcss-browser-comments@^4: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz#bcfc86134df5807f5d3c0eefa191d42136b5e72a" + integrity sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg== + +postcss-calc@^8.2.3: + version "8.2.4" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.4.tgz#77b9c29bfcbe8a07ff6693dc87050828889739a5" + integrity sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q== + dependencies: + postcss-selector-parser "^6.0.9" + postcss-value-parser "^4.2.0" + +postcss-clamp@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-clamp/-/postcss-clamp-4.1.0.tgz#7263e95abadd8c2ba1bd911b0b5a5c9c93e02363" + integrity sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-color-functional-notation@^4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz#21a909e8d7454d3612d1659e471ce4696f28caec" + integrity sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-color-hex-alpha@^8.0.4: + version "8.0.4" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz#c66e2980f2fbc1a63f5b079663340ce8b55f25a5" + integrity sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-color-rebeccapurple@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz#63fdab91d878ebc4dd4b7c02619a0c3d6a56ced0" + integrity sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-colormin@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.0.tgz#3cee9e5ca62b2c27e84fce63affc0cfb5901956a" + integrity sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + colord "^2.9.1" + postcss-value-parser "^4.2.0" + +postcss-convert-values@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz#04998bb9ba6b65aa31035d669a6af342c5f9d393" + integrity sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA== + dependencies: + browserslist "^4.21.4" + postcss-value-parser "^4.2.0" + +postcss-custom-media@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz#c8f9637edf45fef761b014c024cee013f80529ea" + integrity sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-custom-properties@^12.1.10: + version "12.1.11" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz#d14bb9b3989ac4d40aaa0e110b43be67ac7845cf" + integrity sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-custom-selectors@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz#1ab4684d65f30fed175520f82d223db0337239d9" + integrity sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-dir-pseudo-class@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz#2bf31de5de76added44e0a25ecf60ae9f7c7c26c" + integrity sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA== + dependencies: + postcss-selector-parser "^6.0.10" + +postcss-discard-comments@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz#8df5e81d2925af2780075840c1526f0660e53696" + integrity sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ== + +postcss-discard-duplicates@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz#9eb4fe8456706a4eebd6d3b7b777d07bad03e848" + integrity sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw== + +postcss-discard-empty@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz#e57762343ff7f503fe53fca553d18d7f0c369c6c" + integrity sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A== + +postcss-discard-overridden@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz#7e8c5b53325747e9d90131bb88635282fb4a276e" + integrity sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw== + +postcss-double-position-gradients@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz#b96318fdb477be95997e86edd29c6e3557a49b91" + integrity sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^1.1.0" + postcss-value-parser "^4.2.0" + +postcss-env-function@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-4.0.6.tgz#7b2d24c812f540ed6eda4c81f6090416722a8e7a" + integrity sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-flexbugs-fixes@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz#2028e145313074fc9abe276cb7ca14e5401eb49d" + integrity sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ== + +postcss-focus-visible@^6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz#50c9ea9afa0ee657fb75635fabad25e18d76bf9e" + integrity sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw== + dependencies: + postcss-selector-parser "^6.0.9" + +postcss-focus-within@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz#5b1d2ec603195f3344b716c0b75f61e44e8d2e20" + integrity sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ== + dependencies: + postcss-selector-parser "^6.0.9" + +postcss-font-variant@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz#efd59b4b7ea8bb06127f2d031bfbb7f24d32fa66" + integrity sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA== + +postcss-gap-properties@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz#f7e3cddcf73ee19e94ccf7cb77773f9560aa2fff" + integrity sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg== + +postcss-image-set-function@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz#08353bd756f1cbfb3b6e93182c7829879114481f" + integrity sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-import@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0" + integrity sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw== + dependencies: + postcss-value-parser "^4.0.0" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-initial@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-4.0.1.tgz#529f735f72c5724a0fb30527df6fb7ac54d7de42" + integrity sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ== + +postcss-js@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00" + integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ== + dependencies: + camelcase-css "^2.0.1" + +postcss-lab-function@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz#6fe4c015102ff7cd27d1bd5385582f67ebdbdc98" + integrity sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^1.1.0" + postcss-value-parser "^4.2.0" + +postcss-load-config@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz#1ab2571faf84bb078877e1d07905eabe9ebda855" + integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg== + dependencies: + lilconfig "^2.0.5" + yaml "^1.10.2" + +postcss-loader@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.2.1.tgz#0895f7346b1702103d30fdc66e4d494a93c008ef" + integrity sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q== + dependencies: + cosmiconfig "^7.0.0" + klona "^2.0.5" + semver "^7.3.5" + +postcss-logical@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-5.0.4.tgz#ec75b1ee54421acc04d5921576b7d8db6b0e6f73" + integrity sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g== + +postcss-media-minmax@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz#7140bddec173e2d6d657edbd8554a55794e2a5b5" + integrity sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ== + +postcss-merge-longhand@^5.1.7: + version "5.1.7" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz#24a1bdf402d9ef0e70f568f39bdc0344d568fb16" + integrity sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ== + dependencies: + postcss-value-parser "^4.2.0" + stylehacks "^5.1.1" + +postcss-merge-rules@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.3.tgz#8f97679e67cc8d08677a6519afca41edf2220894" + integrity sha512-LbLd7uFC00vpOuMvyZop8+vvhnfRGpp2S+IMQKeuOZZapPRY4SMq5ErjQeHbHsjCUgJkRNrlU+LmxsKIqPKQlA== + dependencies: + browserslist "^4.21.4" + caniuse-api "^3.0.0" + cssnano-utils "^3.1.0" + postcss-selector-parser "^6.0.5" + +postcss-minify-font-values@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz#f1df0014a726083d260d3bd85d7385fb89d1f01b" + integrity sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-minify-gradients@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz#f1fe1b4f498134a5068240c2f25d46fcd236ba2c" + integrity sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw== + dependencies: + colord "^2.9.1" + cssnano-utils "^3.1.0" + postcss-value-parser "^4.2.0" + +postcss-minify-params@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz#c06a6c787128b3208b38c9364cfc40c8aa5d7352" + integrity sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw== + dependencies: + browserslist "^4.21.4" + cssnano-utils "^3.1.0" + postcss-value-parser "^4.2.0" + +postcss-minify-selectors@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz#d4e7e6b46147b8117ea9325a915a801d5fe656c6" + integrity sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg== + dependencies: + postcss-selector-parser "^6.0.5" + +postcss-modules-extract-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" + integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== + +postcss-modules-local-by-default@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" + integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== + dependencies: + icss-utils "^5.0.0" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" + integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-modules-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== + dependencies: + icss-utils "^5.0.0" + +postcss-nested@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.0.tgz#1572f1984736578f360cffc7eb7dca69e30d1735" + integrity sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w== + dependencies: + postcss-selector-parser "^6.0.10" + +postcss-nesting@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-10.2.0.tgz#0b12ce0db8edfd2d8ae0aaf86427370b898890be" + integrity sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA== + dependencies: + "@csstools/selector-specificity" "^2.0.0" + postcss-selector-parser "^6.0.10" + +postcss-normalize-charset@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz#9302de0b29094b52c259e9b2cf8dc0879879f0ed" + integrity sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg== + +postcss-normalize-display-values@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz#72abbae58081960e9edd7200fcf21ab8325c3da8" + integrity sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-positions@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz#ef97279d894087b59325b45c47f1e863daefbb92" + integrity sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-repeat-style@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz#e9eb96805204f4766df66fd09ed2e13545420fb2" + integrity sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-string@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz#411961169e07308c82c1f8c55f3e8a337757e228" + integrity sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-timing-functions@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz#d5614410f8f0b2388e9f240aa6011ba6f52dafbb" + integrity sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-unicode@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz#f67297fca3fea7f17e0d2caa40769afc487aa030" + integrity sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA== + dependencies: + browserslist "^4.21.4" + postcss-value-parser "^4.2.0" + +postcss-normalize-url@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz#ed9d88ca82e21abef99f743457d3729a042adcdc" + integrity sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew== + dependencies: + normalize-url "^6.0.1" + postcss-value-parser "^4.2.0" + +postcss-normalize-whitespace@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz#08a1a0d1ffa17a7cc6efe1e6c9da969cc4493cfa" + integrity sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize/-/postcss-normalize-10.0.1.tgz#464692676b52792a06b06880a176279216540dd7" + integrity sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA== + dependencies: + "@csstools/normalize.css" "*" + postcss-browser-comments "^4" + sanitize.css "*" + +postcss-opacity-percentage@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz#5b89b35551a556e20c5d23eb5260fbfcf5245da6" + integrity sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A== + +postcss-ordered-values@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz#b6fd2bd10f937b23d86bc829c69e7732ce76ea38" + integrity sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ== + dependencies: + cssnano-utils "^3.1.0" + postcss-value-parser "^4.2.0" + +postcss-overflow-shorthand@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz#7ed6486fec44b76f0eab15aa4866cda5d55d893e" + integrity sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-page-break@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-3.0.4.tgz#7fbf741c233621622b68d435babfb70dd8c1ee5f" + integrity sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ== + +postcss-place@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-7.0.5.tgz#95dbf85fd9656a3a6e60e832b5809914236986c4" + integrity sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-preset-env@^7.0.1: + version "7.8.3" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-7.8.3.tgz#2a50f5e612c3149cc7af75634e202a5b2ad4f1e2" + integrity sha512-T1LgRm5uEVFSEF83vHZJV2z19lHg4yJuZ6gXZZkqVsqv63nlr6zabMH3l4Pc01FQCyfWVrh2GaUeCVy9Po+Aag== + dependencies: + "@csstools/postcss-cascade-layers" "^1.1.1" + "@csstools/postcss-color-function" "^1.1.1" + "@csstools/postcss-font-format-keywords" "^1.0.1" + "@csstools/postcss-hwb-function" "^1.0.2" + "@csstools/postcss-ic-unit" "^1.0.1" + "@csstools/postcss-is-pseudo-class" "^2.0.7" + "@csstools/postcss-nested-calc" "^1.0.0" + "@csstools/postcss-normalize-display-values" "^1.0.1" + "@csstools/postcss-oklab-function" "^1.1.1" + "@csstools/postcss-progressive-custom-properties" "^1.3.0" + "@csstools/postcss-stepped-value-functions" "^1.0.1" + "@csstools/postcss-text-decoration-shorthand" "^1.0.0" + "@csstools/postcss-trigonometric-functions" "^1.0.2" + "@csstools/postcss-unset-value" "^1.0.2" + autoprefixer "^10.4.13" + browserslist "^4.21.4" + css-blank-pseudo "^3.0.3" + css-has-pseudo "^3.0.4" + css-prefers-color-scheme "^6.0.3" + cssdb "^7.1.0" + postcss-attribute-case-insensitive "^5.0.2" + postcss-clamp "^4.1.0" + postcss-color-functional-notation "^4.2.4" + postcss-color-hex-alpha "^8.0.4" + postcss-color-rebeccapurple "^7.1.1" + postcss-custom-media "^8.0.2" + postcss-custom-properties "^12.1.10" + postcss-custom-selectors "^6.0.3" + postcss-dir-pseudo-class "^6.0.5" + postcss-double-position-gradients "^3.1.2" + postcss-env-function "^4.0.6" + postcss-focus-visible "^6.0.4" + postcss-focus-within "^5.0.4" + postcss-font-variant "^5.0.0" + postcss-gap-properties "^3.0.5" + postcss-image-set-function "^4.0.7" + postcss-initial "^4.0.1" + postcss-lab-function "^4.2.1" + postcss-logical "^5.0.4" + postcss-media-minmax "^5.0.0" + postcss-nesting "^10.2.0" + postcss-opacity-percentage "^1.1.2" + postcss-overflow-shorthand "^3.0.4" + postcss-page-break "^3.0.4" + postcss-place "^7.0.5" + postcss-pseudo-class-any-link "^7.1.6" + postcss-replace-overflow-wrap "^4.0.0" + postcss-selector-not "^6.0.1" + postcss-value-parser "^4.2.0" + +postcss-pseudo-class-any-link@^7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz#2693b221902da772c278def85a4d9a64b6e617ab" + integrity sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w== + dependencies: + postcss-selector-parser "^6.0.10" + +postcss-reduce-initial@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.1.tgz#c18b7dfb88aee24b1f8e4936541c29adbd35224e" + integrity sha512-//jeDqWcHPuXGZLoolFrUXBDyuEGbr9S2rMo19bkTIjBQ4PqkaO+oI8wua5BOUxpfi97i3PCoInsiFIEBfkm9w== + dependencies: + browserslist "^4.21.4" + caniuse-api "^3.0.0" + +postcss-reduce-transforms@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz#333b70e7758b802f3dd0ddfe98bb1ccfef96b6e9" + integrity sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-replace-overflow-wrap@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz#d2df6bed10b477bf9c52fab28c568b4b29ca4319" + integrity sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw== + +postcss-selector-not@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz#8f0a709bf7d4b45222793fc34409be407537556d" + integrity sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ== + dependencies: + postcss-selector-parser "^6.0.10" + +postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9: + version "6.0.11" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc" + integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-svgo@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz#0a317400ced789f233a28826e77523f15857d80d" + integrity sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA== + dependencies: + postcss-value-parser "^4.2.0" + svgo "^2.7.0" + +postcss-unique-selectors@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz#a9f273d1eacd09e9aa6088f4b0507b18b1b541b6" + integrity sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA== + dependencies: + postcss-selector-parser "^6.0.5" + +postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@^7.0.35: + version "7.0.39" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + +postcss@^8.3.5, postcss@^8.4.18, postcss@^8.4.19, postcss@^8.4.4: + version "8.4.21" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4" + integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^2.8.3: + version "2.8.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.3.tgz#ab697b1d3dd46fb4626fbe2f543afe0cc98d8632" + integrity sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw== + +pretty-bytes@^5.3.0, pretty-bytes@^5.4.1: + version "5.6.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" + integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== + +pretty-error@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6" + integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw== + dependencies: + lodash "^4.17.20" + renderkid "^3.0.0" + +pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + +pretty-format@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.3.tgz#c9fba8cedf99ce50963a11b27d982a9ae90970d5" + integrity sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q== + dependencies: + "@jest/schemas" "^28.1.3" + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +pretty-format@^29.0.0, pretty-format@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.4.1.tgz#0da99b532559097b8254298da7c75a0785b1751c" + integrity sha512-dt/Z761JUVsrIKaY215o1xQJBGlSmTx/h4cSqXqjHLnU1+Kt+mavVE7UgqJJO5ukx5HjSswHfmXz4LjS2oIJfg== + dependencies: + "@jest/schemas" "^29.4.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process-streams@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/process-streams/-/process-streams-1.0.1.tgz#e22c2aadbf788ef0c5754ea5e057e985c87dd691" + integrity sha512-Z+FHhxiBhiQ4t/xTY3Bo2SxZG/CehflyckFsQirAXFRf/BfVnDePzpo58eq9JI4XfFu1RnX5C5EAE6V4sce1+g== + dependencies: + duplex-maker "^1.0.0" + quotemeta "0.0.0" + tempfile "^1.1.0" + +promise@^8.1.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a" + integrity sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg== + dependencies: + asap "~2.0.6" + +prompts@^2.0.1, prompts@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.0, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +psl@^1.1.33: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +punycode@^2.1.0, punycode@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +q@^1.1.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +query-string@^7.1.1: + version "7.1.3" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328" + integrity sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg== + dependencies: + decode-uri-component "^0.2.2" + filter-obj "^1.1.0" + split-on-first "^1.0.0" + strict-uri-encode "^2.0.0" + +querystring@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" + integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +quotemeta@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/quotemeta/-/quotemeta-0.0.0.tgz#51d3a06ee0fcd6e3b501dbd28904351ad7a5a38c" + integrity sha512-1XGObUh7RN5b58vKuAsrlfqT+Rc4vmw8N4pP9gFCq1GFlTdV0Ex/D2Ro1Drvrqj++HPi3ig0Np17XPslELeMRA== + +ra-core@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/ra-core/-/ra-core-4.7.2.tgz#fdfe127da3aa04ff5b53d265ca3a00d6590b77ad" + integrity sha512-05PPxlcHvAgDFRlos3WwR52FA9jFyn1IXQYetvFksyah/1mulSVptXrzG3LdWBE/XazsgHi5JT7G8BdqxJyGzw== + dependencies: + clsx "^1.1.1" + date-fns "^2.19.0" + eventemitter3 "^4.0.7" + inflection "~1.12.0" + jsonexport "^3.2.0" + lodash "~4.17.5" + prop-types "^15.6.1" + query-string "^7.1.1" + react-is "^17.0.2" + react-query "^3.32.1" + +ra-data-json-server@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/ra-data-json-server/-/ra-data-json-server-4.7.2.tgz#1cb69ea68828b59fc4018874dffb274844f309e5" + integrity sha512-O4Mc7vq0HK8i+RyKa2dtvMN3iSvLYJrsmSQqqZnJMGaSwioWZBi9WBuuYRMUCuFlSQx/7y1lzYfrlWPkGci7Mw== + dependencies: + query-string "^7.1.1" + ra-core "^4.7.2" + +ra-i18n-polyglot@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/ra-i18n-polyglot/-/ra-i18n-polyglot-4.7.2.tgz#12e3b0b8d53c58a014f12c9776954b0d9931771e" + integrity sha512-5K9dm0P2fjrPiVhyTxuXCS8K2ZAdlh6YfAVWva+Z4y1jbJVLJZj6JgHtpLPZIO3MW5MeQu7g3E0W/jGUM3N0dQ== + dependencies: + node-polyglot "^2.2.2" + ra-core "^4.7.2" + +ra-language-english@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/ra-language-english/-/ra-language-english-4.7.2.tgz#4e72eb2a78a81b8839f8b81702c73430cbaee6c6" + integrity sha512-F/s6ElTitIsNbxt7LMiaAPdb3vx2vkSeB9goaqWN8lP/ZRSvLEeDQ7Zj3hjHv3nbKI/uglVBHmhZvFJMDjbULQ== + dependencies: + ra-core "^4.7.2" + +ra-ui-materialui@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/ra-ui-materialui/-/ra-ui-materialui-4.7.2.tgz#d4f0ed7810bff6f18e559ae84f0030d8b0906454" + integrity sha512-ZK5xmeVM0549lm2TfYHcIpc5sggzgkJI5hqf8GqUdTk9NtqkBxxaioCTDEwJs2SN0GPoPju2GYQjQYzwcNkp4Q== + dependencies: + autosuggest-highlight "^3.1.1" + clsx "^1.1.1" + css-mediaquery "^0.1.2" + inflection "~1.12.0" + jsonexport "^3.2.0" + lodash "~4.17.5" + prop-types "^15.7.0" + query-string "^7.1.1" + react-dropzone "^12.0.4" + react-error-boundary "^3.1.4" + react-query "^3.32.1" + react-transition-group "^4.4.1" + +raf@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" + integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== + dependencies: + performance-now "^2.1.0" + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +react-admin@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/react-admin/-/react-admin-4.7.2.tgz#e62cc199c6dfff2dcdb209d8449d68e2b75fc618" + integrity sha512-/IleY41n+DIDahI0mULInd5J8iPGrAO8WtH389ExjQ9hIbtBpYMGHEX2GRRwXk5IbcxOo1BqitFQFY3FxdVGWA== + dependencies: + "@emotion/react" "^11.4.1" + "@emotion/styled" "^11.3.0" + "@mui/icons-material" "^5.0.1" + "@mui/material" "^5.0.2" + history "^5.1.0" + ra-core "^4.7.2" + ra-i18n-polyglot "^4.7.2" + ra-language-english "^4.7.2" + ra-ui-materialui "^4.7.2" + react-hook-form "^7.40.0" + react-router "^6.1.0" + react-router-dom "^6.1.0" + +react-app-polyfill@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz#95221e0a9bd259e5ca6b177c7bb1cb6768f68fd7" + integrity sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w== + dependencies: + core-js "^3.19.2" + object-assign "^4.1.1" + promise "^8.1.0" + raf "^3.4.1" + regenerator-runtime "^0.13.9" + whatwg-fetch "^3.6.2" + +react-dev-utils@^12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.1.tgz#ba92edb4a1f379bd46ccd6bcd4e7bc398df33e73" + integrity sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ== + dependencies: + "@babel/code-frame" "^7.16.0" + address "^1.1.2" + browserslist "^4.18.1" + chalk "^4.1.2" + cross-spawn "^7.0.3" + detect-port-alt "^1.1.6" + escape-string-regexp "^4.0.0" + filesize "^8.0.6" + find-up "^5.0.0" + fork-ts-checker-webpack-plugin "^6.5.0" + global-modules "^2.0.0" + globby "^11.0.4" + gzip-size "^6.0.0" + immer "^9.0.7" + is-root "^2.1.0" + loader-utils "^3.2.0" + open "^8.4.0" + pkg-up "^3.1.0" + prompts "^2.4.2" + react-error-overlay "^6.0.11" + recursive-readdir "^2.2.2" + shell-quote "^1.7.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +react-dom@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" + +react-dropzone@^12.0.4: + version "12.1.0" + resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-12.1.0.tgz#e097b37e9da6f9e324efc757b7434ebc6f3dc2cb" + integrity sha512-iBYHA1rbopIvtzokEX4QubO6qk5IF/x3BtKGu74rF2JkQDXnwC4uO/lHKpaw4PJIV6iIAYOlwLv2FpiGyqHNog== + dependencies: + attr-accept "^2.2.2" + file-selector "^0.5.0" + prop-types "^15.8.1" + +react-error-boundary@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz#255db92b23197108757a888b01e5b729919abde0" + integrity sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA== + dependencies: + "@babel/runtime" "^7.12.5" + +react-error-overlay@^6.0.11: + version "6.0.11" + resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" + integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== + +react-hook-form@^7.40.0: + version "7.43.0" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.43.0.tgz#d0c19b5c4ec561fbf8d652869ccb513c11c772e7" + integrity sha512-/rVEz7T0gLdSFwPqutJ1kn2e0sQNyb9ci/hmwEYr2YG0KF/LSuRLvNrf9QWJM+gj88CjDpDW5Bh/1AD7B2+z9Q== + +react-is@^16.13.1, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^17.0.1, react-is@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-is@^18.0.0, react-is@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +react-query@^3.32.1: + version "3.39.3" + resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.3.tgz#4cea7127c6c26bdea2de5fb63e51044330b03f35" + integrity sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g== + dependencies: + "@babel/runtime" "^7.5.5" + broadcast-channel "^3.4.1" + match-sorter "^6.0.2" + +react-refresh@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046" + integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== + +react-router-dom@^6.1.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.8.0.tgz#5e5f4c4b15fdec3965d2ad9d7460d0c61971e744" + integrity sha512-hQouduSTywGJndE86CXJ2h7YEy4HYC6C/uh19etM+79FfQ6cFFFHnHyDlzO4Pq0eBUI96E4qVE5yUjA00yJZGQ== + dependencies: + "@remix-run/router" "1.3.1" + react-router "6.8.0" + +react-router@6.8.0, react-router@^6.1.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.8.0.tgz#dd61fd1ec44daa2cceaef8e6baa00f99a01a650f" + integrity sha512-760bk7y3QwabduExtudhWbd88IBbuD1YfwzpuDUAlJUJ7laIIcqhMvdhSVh1Fur1PE8cGl84L0dxhR3/gvHF7A== + dependencies: + "@remix-run/router" "1.3.1" + +react-scripts@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-5.0.1.tgz#6285dbd65a8ba6e49ca8d651ce30645a6d980003" + integrity sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ== + dependencies: + "@babel/core" "^7.16.0" + "@pmmmwh/react-refresh-webpack-plugin" "^0.5.3" + "@svgr/webpack" "^5.5.0" + babel-jest "^27.4.2" + babel-loader "^8.2.3" + babel-plugin-named-asset-import "^0.3.8" + babel-preset-react-app "^10.0.1" + bfj "^7.0.2" + browserslist "^4.18.1" + camelcase "^6.2.1" + case-sensitive-paths-webpack-plugin "^2.4.0" + css-loader "^6.5.1" + css-minimizer-webpack-plugin "^3.2.0" + dotenv "^10.0.0" + dotenv-expand "^5.1.0" + eslint "^8.3.0" + eslint-config-react-app "^7.0.1" + eslint-webpack-plugin "^3.1.1" + file-loader "^6.2.0" + fs-extra "^10.0.0" + html-webpack-plugin "^5.5.0" + identity-obj-proxy "^3.0.0" + jest "^27.4.3" + jest-resolve "^27.4.2" + jest-watch-typeahead "^1.0.0" + mini-css-extract-plugin "^2.4.5" + postcss "^8.4.4" + postcss-flexbugs-fixes "^5.0.2" + postcss-loader "^6.2.1" + postcss-normalize "^10.0.1" + postcss-preset-env "^7.0.1" + prompts "^2.4.2" + react-app-polyfill "^3.0.0" + react-dev-utils "^12.0.1" + react-refresh "^0.11.0" + resolve "^1.20.0" + resolve-url-loader "^4.0.0" + sass-loader "^12.3.0" + semver "^7.3.5" + source-map-loader "^3.0.0" + style-loader "^3.3.1" + tailwindcss "^3.0.2" + terser-webpack-plugin "^5.2.5" + webpack "^5.64.4" + webpack-dev-server "^4.6.0" + webpack-manifest-plugin "^4.0.2" + workbox-webpack-plugin "^6.4.1" + optionalDependencies: + fsevents "^2.3.2" + +react-transition-group@^4.4.1, react-transition-group@^4.4.5: + version "4.4.5" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" + integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + +react@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + dependencies: + loose-envify "^1.1.0" + +read-cache@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA== + dependencies: + pify "^2.3.0" + +readable-stream@3, readable-stream@^3.0.6: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +recursive-readdir@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.3.tgz#e726f328c0d69153bcabd5c322d3195252379372" + integrity sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA== + dependencies: + minimatch "^3.0.5" + +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + +regenerate-unicode-properties@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" + integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.9: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + +regenerator-transform@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56" + integrity sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg== + dependencies: + "@babel/runtime" "^7.8.4" + +regex-parser@^2.2.11: + version "2.2.11" + resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.11.tgz#3b37ec9049e19479806e878cabe7c1ca83ccfe58" + integrity sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q== + +regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + functions-have-names "^1.2.2" + +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +regexpu-core@^5.2.1: + version "5.2.2" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.2.2.tgz#3e4e5d12103b64748711c3aad69934d7718e75fc" + integrity sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^10.1.0" + regjsgen "^0.7.1" + regjsparser "^0.9.1" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" + +regjsgen@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.7.1.tgz#ee5ef30e18d3f09b7c369b76e7c2373ed25546f6" + integrity sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA== + +regjsparser@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" + integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== + dependencies: + jsesc "~0.5.0" + +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== + +remove-accents@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5" + integrity sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA== + +remove-accents@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.4.tgz#73704abf7dae3764295d475d2b6afac4ea23e4d9" + integrity sha512-EpFcOa/ISetVHEXqu+VwI96KZBmq+a8LJnGkaeFw45epGlxIZz5dhEEnNZMsQXgORu3qaMoLX4qJCzOik6ytAg== + +renderkid@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" + integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg== + dependencies: + css-select "^4.1.3" + dom-converter "^0.2.0" + htmlparser2 "^6.1.0" + lodash "^4.17.21" + strip-ansi "^6.0.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-url-loader@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz#d50d4ddc746bb10468443167acf800dcd6c3ad57" + integrity sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA== + dependencies: + adjust-sourcemap-loader "^4.0.0" + convert-source-map "^1.7.0" + loader-utils "^2.0.0" + postcss "^7.0.35" + source-map "0.6.1" + +resolve.exports@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999" + integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== + +resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.1: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^2.0.0-next.4: + version "2.0.0-next.4" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" + integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rollup-plugin-terser@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" + integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ== + dependencies: + "@babel/code-frame" "^7.10.4" + jest-worker "^26.2.1" + serialize-javascript "^4.0.0" + terser "^5.0.0" + +rollup@^2.43.1: + version "2.79.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7" + integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw== + optionalDependencies: + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sanitize.css@*: + version "13.0.0" + resolved "https://registry.yarnpkg.com/sanitize.css/-/sanitize.css-13.0.0.tgz#2675553974b27964c75562ade3bd85d79879f173" + integrity sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA== + +sass-loader@^12.3.0: + version "12.6.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-12.6.0.tgz#5148362c8e2cdd4b950f3c63ac5d16dbfed37bcb" + integrity sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA== + dependencies: + klona "^2.0.4" + neo-async "^2.6.2" + +sax@~1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== + dependencies: + loose-envify "^1.1.0" + +schema-utils@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" + integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== + dependencies: + "@types/json-schema" "^7.0.4" + ajv "^6.12.2" + ajv-keywords "^3.4.1" + +schema-utils@^2.6.5: + version "2.7.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" + integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== + dependencies: + "@types/json-schema" "^7.0.5" + ajv "^6.12.4" + ajv-keywords "^3.5.2" + +schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" + integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.8.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.0.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== + +selfsigned@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.1.1.tgz#18a7613d714c0cd3385c48af0075abf3f266af61" + integrity sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ== + dependencies: + node-forge "^1" + +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + dependencies: + lru-cache "^6.0.0" + +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serialize-javascript@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" + integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== + dependencies: + randombytes "^2.1.0" + +serialize-javascript@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" + integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== + dependencies: + randombytes "^2.1.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw== + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@^1.7.3: + version "1.7.4" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.4.tgz#33fe15dee71ab2a81fcbd3a52106c5cfb9fb75d8" + integrity sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +simple-zstd@^1.4.0: + version "1.4.2" + resolved "https://registry.yarnpkg.com/simple-zstd/-/simple-zstd-1.4.2.tgz#4f5b7b05dfd2930b03092eb0c0cd13a44bad4b34" + integrity sha512-kGYEvT33M5XfyQvvW4wxl3eKcWbdbCc1V7OZzuElnaXft0qbVzoIIXHXiCm3JCUki+MZKKmvjl8p2VGLJc5Y/A== + dependencies: + is-zst "^1.0.0" + peek-stream "^1.1.3" + process-streams "^1.0.1" + through2 "^4.0.2" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slash@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" + integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== + +sockjs@^0.3.24: + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== + dependencies: + faye-websocket "^0.11.3" + uuid "^8.3.2" + websocket-driver "^0.7.4" + +source-list-map@^2.0.0, source-list-map@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-js@^1.0.1, source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-loader@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-3.0.2.tgz#af23192f9b344daa729f6772933194cc5fa54fee" + integrity sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg== + dependencies: + abab "^2.0.5" + iconv-lite "^0.6.3" + source-map-js "^1.0.1" + +source-map-support@^0.5.6, source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +source-map@^0.7.3: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + +source-map@^0.8.0-beta.0: + version "0.8.0-beta.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11" + integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA== + dependencies: + whatwg-url "^7.0.0" + +sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +split-on-first@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" + integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +stackframe@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" + integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== + dependencies: + internal-slot "^1.0.4" + +stream-shift@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== + +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-length@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-5.0.1.tgz#3d647f497b6e8e8d41e422f7e0b23bc536c8381e" + integrity sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow== + dependencies: + char-regex "^2.0.0" + strip-ansi "^7.0.1" + +string-natural-compare@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" + integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.matchall@^4.0.6, string.prototype.matchall@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" + integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.4.3" + side-channel "^1.0.4" + +string.prototype.trim@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimend@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" + integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimstart@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" + integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +stringify-object@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" + integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== + dependencies: + get-own-enumerable-property-symbols "^3.0.0" + is-obj "^1.0.1" + is-regexp "^1.0.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" + integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== + dependencies: + ansi-regex "^6.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-comments@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-2.0.1.tgz#4ad11c3fbcac177a67a40ac224ca339ca1c1ba9b" + integrity sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +style-loader@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" + integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ== + +stylehacks@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.1.tgz#7934a34eb59d7152149fa69d6e9e56f2fc34bcc9" + integrity sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw== + dependencies: + browserslist "^4.21.4" + postcss-selector-parser "^6.0.4" + +stylis@4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7" + integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" + integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +svg-parser@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" + integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== + +svgo@^1.2.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== + dependencies: + chalk "^2.4.1" + coa "^2.0.2" + css-select "^2.0.0" + css-select-base-adapter "^0.1.1" + css-tree "1.0.0-alpha.37" + csso "^4.0.2" + js-yaml "^3.13.1" + mkdirp "~0.5.1" + object.values "^1.1.0" + sax "~1.2.4" + stable "^0.1.8" + unquote "~1.1.1" + util.promisify "~1.0.0" + +svgo@^2.7.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" + integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== + dependencies: + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^4.1.3" + css-tree "^1.1.3" + csso "^4.2.0" + picocolors "^1.0.0" + stable "^0.1.8" + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +tailwindcss@^3.0.2: + version "3.2.4" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.2.4.tgz#afe3477e7a19f3ceafb48e4b083e292ce0dc0250" + integrity sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ== + dependencies: + arg "^5.0.2" + chokidar "^3.5.3" + color-name "^1.1.4" + detective "^5.2.1" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.12" + glob-parent "^6.0.2" + is-glob "^4.0.3" + lilconfig "^2.0.6" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.18" + postcss-import "^14.1.0" + postcss-js "^4.0.0" + postcss-load-config "^3.1.4" + postcss-nested "6.0.0" + postcss-selector-parser "^6.0.10" + postcss-value-parser "^4.2.0" + quick-lru "^5.1.1" + resolve "^1.22.1" + +tapable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +temp-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e" + integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== + +tempfile@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tempfile/-/tempfile-1.1.1.tgz#5bcc4eaecc4ab2c707d8bc11d99ccc9a2cb287f2" + integrity sha512-NjT12fW6pSEKz1eVcADgaKfeM+XZ4+zSaqVz46XH7+CiEwcelnwtGWRRjF1p+xyW2PVgKKKS2UUw1LzRelntxg== + dependencies: + os-tmpdir "^1.0.0" + uuid "^2.0.1" + +tempy@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tempy/-/tempy-0.6.0.tgz#65e2c35abc06f1124a97f387b08303442bde59f3" + integrity sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw== + dependencies: + is-stream "^2.0.0" + temp-dir "^2.0.0" + type-fest "^0.16.0" + unique-string "^2.0.0" + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.2.5: + version "5.3.6" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz#5590aec31aa3c6f771ce1b1acca60639eab3195c" + integrity sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ== + dependencies: + "@jridgewell/trace-mapping" "^0.3.14" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" + terser "^5.14.1" + +terser@^5.0.0, terser@^5.10.0, terser@^5.14.1: + version "5.16.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.2.tgz#8f495819439e8b5c150e7530fc434a6e70ea18b2" + integrity sha512-JKuM+KvvWVqT7muHVyrwv7FVRPnmHDwF6XwoIxdbF5Witi0vu99RYpxDexpJndXt3jbZZmmWr2/mQa6HvSNdSg== + dependencies: + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" + commander "^2.20.0" + source-map-support "~0.5.20" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +throat@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe" + integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ== + +through2@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through2@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" + integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== + dependencies: + readable-stream "3" + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tough-cookie@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.2.tgz#e53e84b85f24e0b65dd526f46628db6c85f6b874" + integrity sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA== + dependencies: + punycode "^2.1.0" + +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + +tryer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" + integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== + +tsconfig-paths@^3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.0.3: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.16.0: + version "0.16.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.16.0.tgz#3240b891a78b0deae910dbeb86553e552a148860" + integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typeface-roboto-mono@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/typeface-roboto-mono/-/typeface-roboto-mono-1.1.13.tgz#2af8662db8f9119c00efd55d6ed8877d2a69ec94" + integrity sha512-pnzDc70b7ywJHin/BUFL7HZX8DyOTBLT2qxlJ92eH1UJOFcENIBXa9IZrxsJX/gEKjbEDKhW5vz/TKRBNk/ufQ== + +typeface-titillium-web@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/typeface-titillium-web/-/typeface-titillium-web-1.1.13.tgz#3fb50c8c7ea0cbc3531cad7f1a23d7218aeb24be" + integrity sha512-R21mXf9hoqle+dgR7k6C6QUN2XElopQNsTDYI5DoU1buuYayVvzn2jd2ihKJTwM/hJsltLrlJUkyumc3FFgevA== + +typescript@^4.4.2: + version "4.9.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78" + integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unload@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7" + integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA== + dependencies: + "@babel/runtime" "^7.6.2" + detect-node "^2.0.4" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg== + +upath@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +update-browserslist-db@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" + integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +util.promisify@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + integrity sha512-FULf7fayPdpASncVy4DLh3xydlXEJJpvIELjYjNeQWYUZ9pclcpvCZSr2gkmN2FrrGcI7G/cJsIEwk5/8vfXpg== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-to-istanbul@^8.1.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" + integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +walker@^1.0.7: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +warning@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + +watchpack@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +web-vitals@^2.1.0: + version "2.1.4" + resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-2.1.4.tgz#76563175a475a5e835264d373704f9dde718290c" + integrity sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg== + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + +webpack-dev-middleware@^5.3.1: + version "5.3.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f" + integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA== + dependencies: + colorette "^2.0.10" + memfs "^3.4.3" + mime-types "^2.1.31" + range-parser "^1.2.1" + schema-utils "^4.0.0" + +webpack-dev-server@^4.6.0: + version "4.11.1" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz#ae07f0d71ca0438cf88446f09029b92ce81380b5" + integrity sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw== + dependencies: + "@types/bonjour" "^3.5.9" + "@types/connect-history-api-fallback" "^1.3.5" + "@types/express" "^4.17.13" + "@types/serve-index" "^1.9.1" + "@types/serve-static" "^1.13.10" + "@types/sockjs" "^0.3.33" + "@types/ws" "^8.5.1" + ansi-html-community "^0.0.8" + bonjour-service "^1.0.11" + chokidar "^3.5.3" + colorette "^2.0.10" + compression "^1.7.4" + connect-history-api-fallback "^2.0.0" + default-gateway "^6.0.3" + express "^4.17.3" + graceful-fs "^4.2.6" + html-entities "^2.3.2" + http-proxy-middleware "^2.0.3" + ipaddr.js "^2.0.1" + open "^8.0.9" + p-retry "^4.5.0" + rimraf "^3.0.2" + schema-utils "^4.0.0" + selfsigned "^2.1.1" + serve-index "^1.9.1" + sockjs "^0.3.24" + spdy "^4.0.2" + webpack-dev-middleware "^5.3.1" + ws "^8.4.2" + +webpack-manifest-plugin@^4.0.2: + version "4.1.1" + resolved "https://registry.yarnpkg.com/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz#10f8dbf4714ff93a215d5a45bcc416d80506f94f" + integrity sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow== + dependencies: + tapable "^2.0.0" + webpack-sources "^2.2.0" + +webpack-sources@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack-sources@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.1.tgz#570de0af163949fe272233c2cefe1b56f74511fd" + integrity sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA== + dependencies: + source-list-map "^2.0.1" + source-map "^0.6.1" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@^5.64.4: + version "5.75.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.75.0.tgz#1e440468647b2505860e94c9ff3e44d5b582c152" + integrity sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^0.0.51" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.7.1" + acorn-import-assertions "^1.7.6" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.10.0" + es-module-lexer "^0.9.0" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.4.0" + webpack-sources "^3.2.3" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-fetch@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" + integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" + +which-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" + integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.10" + +which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.3, word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +workbox-background-sync@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-6.5.4.tgz#3141afba3cc8aa2ae14c24d0f6811374ba8ff6a9" + integrity sha512-0r4INQZMyPky/lj4Ou98qxcThrETucOde+7mRGJl13MPJugQNKeZQOdIJe/1AchOP23cTqHcN/YVpD6r8E6I8g== + dependencies: + idb "^7.0.1" + workbox-core "6.5.4" + +workbox-broadcast-update@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-broadcast-update/-/workbox-broadcast-update-6.5.4.tgz#8441cff5417cd41f384ba7633ca960a7ffe40f66" + integrity sha512-I/lBERoH1u3zyBosnpPEtcAVe5lwykx9Yg1k6f8/BGEPGaMMgZrwVrqL1uA9QZ1NGGFoyE6t9i7lBjOlDhFEEw== + dependencies: + workbox-core "6.5.4" + +workbox-build@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-build/-/workbox-build-6.5.4.tgz#7d06d31eb28a878817e1c991c05c5b93409f0389" + integrity sha512-kgRevLXEYvUW9WS4XoziYqZ8Q9j/2ziJYEtTrjdz5/L/cTUa2XfyMP2i7c3p34lgqJ03+mTiz13SdFef2POwbA== + dependencies: + "@apideck/better-ajv-errors" "^0.3.1" + "@babel/core" "^7.11.1" + "@babel/preset-env" "^7.11.0" + "@babel/runtime" "^7.11.2" + "@rollup/plugin-babel" "^5.2.0" + "@rollup/plugin-node-resolve" "^11.2.1" + "@rollup/plugin-replace" "^2.4.1" + "@surma/rollup-plugin-off-main-thread" "^2.2.3" + ajv "^8.6.0" + common-tags "^1.8.0" + fast-json-stable-stringify "^2.1.0" + fs-extra "^9.0.1" + glob "^7.1.6" + lodash "^4.17.20" + pretty-bytes "^5.3.0" + rollup "^2.43.1" + rollup-plugin-terser "^7.0.0" + source-map "^0.8.0-beta.0" + stringify-object "^3.3.0" + strip-comments "^2.0.1" + tempy "^0.6.0" + upath "^1.2.0" + workbox-background-sync "6.5.4" + workbox-broadcast-update "6.5.4" + workbox-cacheable-response "6.5.4" + workbox-core "6.5.4" + workbox-expiration "6.5.4" + workbox-google-analytics "6.5.4" + workbox-navigation-preload "6.5.4" + workbox-precaching "6.5.4" + workbox-range-requests "6.5.4" + workbox-recipes "6.5.4" + workbox-routing "6.5.4" + workbox-strategies "6.5.4" + workbox-streams "6.5.4" + workbox-sw "6.5.4" + workbox-window "6.5.4" + +workbox-cacheable-response@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-cacheable-response/-/workbox-cacheable-response-6.5.4.tgz#a5c6ec0c6e2b6f037379198d4ef07d098f7cf137" + integrity sha512-DCR9uD0Fqj8oB2TSWQEm1hbFs/85hXXoayVwFKLVuIuxwJaihBsLsp4y7J9bvZbqtPJ1KlCkmYVGQKrBU4KAug== + dependencies: + workbox-core "6.5.4" + +workbox-core@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-core/-/workbox-core-6.5.4.tgz#df48bf44cd58bb1d1726c49b883fb1dffa24c9ba" + integrity sha512-OXYb+m9wZm8GrORlV2vBbE5EC1FKu71GGp0H4rjmxmF4/HLbMCoTFws87M3dFwgpmg0v00K++PImpNQ6J5NQ6Q== + +workbox-expiration@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-expiration/-/workbox-expiration-6.5.4.tgz#501056f81e87e1d296c76570bb483ce5e29b4539" + integrity sha512-jUP5qPOpH1nXtjGGh1fRBa1wJL2QlIb5mGpct3NzepjGG2uFFBn4iiEBiI9GUmfAFR2ApuRhDydjcRmYXddiEQ== + dependencies: + idb "^7.0.1" + workbox-core "6.5.4" + +workbox-google-analytics@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-google-analytics/-/workbox-google-analytics-6.5.4.tgz#c74327f80dfa4c1954cbba93cd7ea640fe7ece7d" + integrity sha512-8AU1WuaXsD49249Wq0B2zn4a/vvFfHkpcFfqAFHNHwln3jK9QUYmzdkKXGIZl9wyKNP+RRX30vcgcyWMcZ9VAg== + dependencies: + workbox-background-sync "6.5.4" + workbox-core "6.5.4" + workbox-routing "6.5.4" + workbox-strategies "6.5.4" + +workbox-navigation-preload@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-navigation-preload/-/workbox-navigation-preload-6.5.4.tgz#ede56dd5f6fc9e860a7e45b2c1a8f87c1c793212" + integrity sha512-IIwf80eO3cr8h6XSQJF+Hxj26rg2RPFVUmJLUlM0+A2GzB4HFbQyKkrgD5y2d84g2IbJzP4B4j5dPBRzamHrng== + dependencies: + workbox-core "6.5.4" + +workbox-precaching@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-precaching/-/workbox-precaching-6.5.4.tgz#740e3561df92c6726ab5f7471e6aac89582cab72" + integrity sha512-hSMezMsW6btKnxHB4bFy2Qfwey/8SYdGWvVIKFaUm8vJ4E53JAY+U2JwLTRD8wbLWoP6OVUdFlXsTdKu9yoLTg== + dependencies: + workbox-core "6.5.4" + workbox-routing "6.5.4" + workbox-strategies "6.5.4" + +workbox-range-requests@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-range-requests/-/workbox-range-requests-6.5.4.tgz#86b3d482e090433dab38d36ae031b2bb0bd74399" + integrity sha512-Je2qR1NXCFC8xVJ/Lux6saH6IrQGhMpDrPXWZWWS8n/RD+WZfKa6dSZwU+/QksfEadJEr/NfY+aP/CXFFK5JFg== + dependencies: + workbox-core "6.5.4" + +workbox-recipes@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-recipes/-/workbox-recipes-6.5.4.tgz#cca809ee63b98b158b2702dcfb741b5cc3e24acb" + integrity sha512-QZNO8Ez708NNwzLNEXTG4QYSKQ1ochzEtRLGaq+mr2PyoEIC1xFW7MrWxrONUxBFOByksds9Z4//lKAX8tHyUA== + dependencies: + workbox-cacheable-response "6.5.4" + workbox-core "6.5.4" + workbox-expiration "6.5.4" + workbox-precaching "6.5.4" + workbox-routing "6.5.4" + workbox-strategies "6.5.4" + +workbox-routing@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-routing/-/workbox-routing-6.5.4.tgz#6a7fbbd23f4ac801038d9a0298bc907ee26fe3da" + integrity sha512-apQswLsbrrOsBUWtr9Lf80F+P1sHnQdYodRo32SjiByYi36IDyL2r7BH1lJtFX8fwNHDa1QOVY74WKLLS6o5Pg== + dependencies: + workbox-core "6.5.4" + +workbox-strategies@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-strategies/-/workbox-strategies-6.5.4.tgz#4edda035b3c010fc7f6152918370699334cd204d" + integrity sha512-DEtsxhx0LIYWkJBTQolRxG4EI0setTJkqR4m7r4YpBdxtWJH1Mbg01Cj8ZjNOO8etqfA3IZaOPHUxCs8cBsKLw== + dependencies: + workbox-core "6.5.4" + +workbox-streams@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-streams/-/workbox-streams-6.5.4.tgz#1cb3c168a6101df7b5269d0353c19e36668d7d69" + integrity sha512-FXKVh87d2RFXkliAIheBojBELIPnWbQdyDvsH3t74Cwhg0fDheL1T8BqSM86hZvC0ZESLsznSYWw+Va+KVbUzg== + dependencies: + workbox-core "6.5.4" + workbox-routing "6.5.4" + +workbox-sw@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-sw/-/workbox-sw-6.5.4.tgz#d93e9c67924dd153a61367a4656ff4d2ae2ed736" + integrity sha512-vo2RQo7DILVRoH5LjGqw3nphavEjK4Qk+FenXeUsknKn14eCNedHOXWbmnvP4ipKhlE35pvJ4yl4YYf6YsJArA== + +workbox-webpack-plugin@^6.4.1: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-webpack-plugin/-/workbox-webpack-plugin-6.5.4.tgz#baf2d3f4b8f435f3469887cf4fba2b7fac3d0fd7" + integrity sha512-LmWm/zoaahe0EGmMTrSLUi+BjyR3cdGEfU3fS6PN1zKFYbqAKuQ+Oy/27e4VSXsyIwAw8+QDfk1XHNGtZu9nQg== + dependencies: + fast-json-stable-stringify "^2.1.0" + pretty-bytes "^5.4.1" + upath "^1.2.0" + webpack-sources "^1.4.3" + workbox-build "6.5.4" + +workbox-window@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-6.5.4.tgz#d991bc0a94dff3c2dbb6b84558cff155ca878e91" + integrity sha512-HnLZJDwYBE+hpG25AQBO8RUWBJRaCsI9ksQJEp3aCOFCaG5kqaToAYXFRAHxzRluM2cQbGzdQF5rjKPWPA1fug== + dependencies: + "@types/trusted-types" "^2.0.2" + workbox-core "6.5.4" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@^7.4.6: + version "7.5.9" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + +ws@^8.4.2: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.0.tgz#485074cc392689da78e1828a9ff23585e06cddd8" + integrity sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig== + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +xtend@^4.0.2, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/dev-console/.env b/dev-console/.env new file mode 100644 index 000000000..c4573d250 --- /dev/null +++ b/dev-console/.env @@ -0,0 +1,5 @@ +REACT_APP_API_URL= +REACT_APP_USER_CONSOLE=/console/user +REACT_APP_DEVELOPER_CONSOLE=/console/dev +REACT_APP_ADMIN_CONSOLE=/console/admin +REACT_APP_CONTEXT_PATH="/console/dev" diff --git a/dev-console/.env.development b/dev-console/.env.development new file mode 100644 index 000000000..74b4ef07d --- /dev/null +++ b/dev-console/.env.development @@ -0,0 +1,5 @@ +REACT_APP_API_URL=http://localhost:8080 +REACT_APP_USER_CONSOLE=http://localhost:8080/console/user +REACT_APP_DEVELOPER_CONSOLE=http://localhost:8080/console/dev +REACT_APP_ADMIN_CONSOLE=http://localhost:8080/console/admin +REACT_APP_CONTEXT_PATH="" diff --git a/dev-console/.eslintrc.js b/dev-console/.eslintrc.js new file mode 100644 index 000000000..962461afa --- /dev/null +++ b/dev-console/.eslintrc.js @@ -0,0 +1,25 @@ +module.exports = { + "extends": [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:react/jsx-runtime", + "plugin:react-hooks/recommended", + "prettier" + ], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "rules": { + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": "error" +}, + "env": { + "browser": true, + "es2021": true, + "node": true + }, + "settings": { + "react": { + "version": "detect" + } + } +} diff --git a/dev-console/.gitignore b/dev-console/.gitignore new file mode 100644 index 000000000..01335afa1 --- /dev/null +++ b/dev-console/.gitignore @@ -0,0 +1,25 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.vite + +# testing +/coverage + +# production +/build +/dist + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/dev-console/.prettierrc.js b/dev-console/.prettierrc.js new file mode 100644 index 000000000..d2ba7f89f --- /dev/null +++ b/dev-console/.prettierrc.js @@ -0,0 +1,15 @@ +module.exports = { + arrowParens: 'avoid', + bracketSpacing: true, + jsxBracketSameLine: false, + jsxSingleQuote: false, + printWidth: 80, + quoteProps: 'as-needed', + rangeStart: 0, + rangeEnd: Infinity, + semi: true, + singleQuote: true, + tabWidth: 4, + trailingComma: 'es5', + useTabs: false +} diff --git a/dev-console/.vscode/launch.json b/dev-console/.vscode/launch.json new file mode 100644 index 000000000..a14d56e5e --- /dev/null +++ b/dev-console/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "request": "launch", + "name": "Launch Chrome against localhost", + "url": "http://localhost:5173", + "webRoot": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/dev-console/README.md b/dev-console/README.md new file mode 100644 index 000000000..b58e0af83 --- /dev/null +++ b/dev-console/README.md @@ -0,0 +1,46 @@ +# Getting Started with Create React App + +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `yarn start` + +Runs the app in the development mode.\ +Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.\ +You will also see any lint errors in the console. + +### `yarn test` + +Launches the test runner in the interactive watch mode.\ +See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `yarn build` + +Builds the app for production to the `build` folder.\ +It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.\ +Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `yarn eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). diff --git a/dev-console/i18ngenerator.js b/dev-console/i18ngenerator.js new file mode 100644 index 000000000..13d411d59 --- /dev/null +++ b/dev-console/i18ngenerator.js @@ -0,0 +1,73 @@ +require('process'); +const _ = require('lodash'); +const { readFileSync, writeFileSync } = require('fs'); +const { parseArgs } = require('node:util'); +const readline = require('readline'); + +let obj = {}; +let defaultValue = ''; +let prefix = null; +let output = null; + +const args = parseArgs({ + options: { + file: { + type: 'string', + short: 'f', + }, + defaultValue: { + type: 'string', + short: 'd', + }, + prefix: { + type: 'string', + short: 'p', + }, + output: { + type: 'string', + short: 'o', + }, + }, +}); + +if (args.values.file) { + //read json from file as obj + const data = readFileSync(args.values.file); + if (data) { + obj = JSON.parse(data); + } +} + +if (args.values.defaultValue) { + defaultValue = args.values.defaultValue; +} +if (args.values.prefix) { + prefix = args.values.prefix; +} +if (args.values.output) { + output = args.values.output; +} + +(async function () { + for await (const line of readline.createInterface({ + input: process.stdin, + })) { + let input = line.replace(/(\r\n|\n|\r)/gm, ''); + if (prefix) { + input = input.substring(prefix.length + 1); + } + + if (!_.get(obj, input)) { + const value = defaultValue ? defaultValue : input; + _.set(obj, input, value); + } + } + + const result = JSON.stringify(obj, null, 4); + if (output) { + console.log(`write result to ${output}`); + writeFileSync(output, result, { encoding: 'utf8' }); + } else { + process.stdout.write(result); + } +})(); diff --git a/dev-console/index.html b/dev-console/index.html new file mode 100644 index 000000000..6af5f1754 --- /dev/null +++ b/dev-console/index.html @@ -0,0 +1,128 @@ + + + + + + + + + platformadmin + + + + + + + + +
+
+
Loading...
+
+
+ + diff --git a/dev-console/package.json b/dev-console/package.json new file mode 100644 index 000000000..d14c6bb18 --- /dev/null +++ b/dev-console/package.json @@ -0,0 +1,67 @@ +{ + "name": "dev-console", + "version": "1.0.0", + "private": true, + "license": "Apache-2.0", + "dependencies": { + "@dslab/ra-ace-editor": "^1.1.0", + "@dslab/ra-datagrid-input": "^1.0.0", + "@dslab/ra-delete-dialog-button": "^1.0.0", + "@dslab/ra-dialog-crud": "^1.0.2", + "@dslab/ra-export-record-button": "^1.0.0", + "@dslab/ra-inspect-button": "^1.0.3", + "@dslab/ra-jsonschema-input": "^2.1.1", + "@dslab/ra-language-italian": "^1.0.0", + "@dslab/ra-root-selector": "^1.0.3", + "@dslab/ra-stepper": "^1.1.1", + "@mui/icons-material": "^5.11.0", + "@mui/material": "^5.11.7", + "@simplewebauthn/browser": "^7.0.1", + "@testing-library/jest-dom": "^5.14.1", + "@testing-library/react": "^13.0.0", + "@testing-library/user-event": "^13.2.1", + "env-cmd": "^10.1.0", + "querystring": "^0.2.1", + "ra-data-json-server": "^4.7.2", + "ra-input-rich-text": "^4.14.4", + "react": "^18.2.0", + "react-admin": "4.11.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.18.0", + "typeface-roboto-mono": "^1.1.13", + "typeface-titillium-web": "^1.1.13" + }, + "scripts": { + "start": "env-cmd -f .env.development vite", + "start:local": "env-cmd -f .env.local vite", + "build": "env-cmd -f .env vite build", + "dist": "env-cmd -f .env vite build && gzipper c --gzip --brotli --remove-larger --skip-compressed ./dist", + "serve": "env-cmd -f .env vite preview", + "lint": "eslint --ext .js,.ts,.tsx \"./src/**/*.{js,ts,tsx}\" ", + "prettier": "prettier --config ./.prettierrc.js --write --list-different \"src/**/*.{js,ts,tsx,css}\"", + "i18n:en:fields": "grep -r \"field\\.\" src/ | awk -F\"'|\\\"\" '{print $2}' | grep '^field.' | sort -u | node i18ngenerator.js -p field -f src/i18n/en/fields.json -o src/i18n/en/fields.json", + "i18n:en:pages": "grep -r \"page\\.\" src/ | awk -F\"'|\\\"\" '{print $2}' | grep '^page.' | sort -u | node i18ngenerator.js -p page -f src/i18n/en/pages.json -o src/i18n/en/pages.json", + "i18n:en:errors": "grep -r \"error\\.\" src/ | awk -F\"'|\\\"\" '{print $2}' | grep '^error.' | sort -u | node i18ngenerator.js -p error -f src/i18n/en/errors.json -o src/i18n/en/errors.json", + "i18n:en:messages": "grep -r \"message\\.\" src/ | awk -F\\\"'|\"\" '{print $2}' | grep '^message.' | sort -u | node i18ngenerator.js -p message -f src/i18n/en/messages.json -o src/i18n/en/messages.json", + "i18n:en:tabs": "grep -r \"tab\\.\" src/ | awk -F\"'|\\\"\" '{print $2}' | grep '^tab.' | sort -u | node i18ngenerator.js -p tab -f src/i18n/en/tabs.json -o src/i18n/en/tabs.json" + }, + "devDependencies": { + "@simplewebauthn/typescript-types": "^7.0.0", + "@types/jest": "^27.0.1", + "@types/node": "^18.16.1", + "@types/react": "^18.2.56", + "@types/react-dom": "^18.2.19", + "@typescript-eslint/eslint-plugin": "7.1.0", + "@typescript-eslint/parser": "7.1.0", + "@vitejs/plugin-react": "^4.2.1", + "eslint": "^8.56.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-react": "^7.32.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.5", + "gzipper": "^7.2.0", + "prettier": "^2.8.8", + "typescript": "^5.2.2", + "vite": "^5.1.4" + } +} diff --git a/dev-console/public/favicon.ico b/dev-console/public/favicon.ico new file mode 100644 index 000000000..801e2577b Binary files /dev/null and b/dev-console/public/favicon.ico differ diff --git a/dev-console/public/manifest.json b/dev-console/public/manifest.json new file mode 100644 index 000000000..7c0574084 --- /dev/null +++ b/dev-console/public/manifest.json @@ -0,0 +1,9 @@ +{ + "short_name": "dev-console", + "name": "AAC dev console", + "icons": [], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/dev-console/public/robots.txt b/dev-console/public/robots.txt new file mode 100644 index 000000000..e9e57dc4d --- /dev/null +++ b/dev-console/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/dev-console/src/App.css b/dev-console/src/App.css new file mode 100644 index 000000000..78b8850cf --- /dev/null +++ b/dev-console/src/App.css @@ -0,0 +1,38 @@ +.App { + text-align: center; +} + +.App-logo { + height: 40vmin; + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + .App-logo { + animation: App-logo-spin infinite 20s linear; + } +} + +.App-header { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; +} + +.App-link { + color: #61dafb; +} + +@keyframes App-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/dev-console/src/App.tsx b/dev-console/src/App.tsx new file mode 100644 index 000000000..66c0d1da3 --- /dev/null +++ b/dev-console/src/App.tsx @@ -0,0 +1,127 @@ +import { Admin, Resource } from 'react-admin'; +import { BrowserRouter } from 'react-router-dom'; + +import appDataProvider from './dataProvider'; +import appAuthProvider from './authProvider'; +import i18nProvider from './i18nProvider'; +import themeProvider from './themeProvider'; +import './App.css'; +import AppLayout from './layout/AppLayout'; + +import { + RootSelectorContextProvider, + RootSelectorInitialWrapper, +} from '@dslab/ra-root-selector'; + +// pages +import DevDashboard from './pages/dashboard'; +import { LoginPage } from './pages/login'; + +// resources +import myrealmsDefinition from './myrealms'; +import appsDefinition from './apps'; +import groupsDefinition from './group'; +import rolesDefinition from './roles'; +import usersDefinition from './users'; +import idpsDefinition from './idps'; +import apsDefinition from './aps'; +import apiResourcesDefinition from './resources'; +import auditDefinition from './audit'; +import serviceDefinition from './service'; +import attributeSetDefinition from './attributeset'; +import scopesDefinition from './scopes'; + +import { RealmSelectorList } from './myrealms/RealmList'; + +//config +const CONTEXT_PATH: string = + import.meta.env.BASE_URL || + (globalThis as any).REACT_APP_CONTEXT_PATH || + (process.env.REACT_APP_CONTEXT_PATH as string); +const API_URL: string = process.env.REACT_APP_API_URL as string; +const dataProvider = appDataProvider(API_URL); +const authProvider = appAuthProvider(API_URL); +export const DEFAULT_LANGUAGES = ['en', 'it', 'es', 'lv', 'de']; + +const DevApp = () => { + return ( + } + > + } + authCallbackPage={false} + requireAuth + disableTelemetry + > + + + + + + + + + + + + + + + + + + + ); +}; +const InitialWrapper = () => { + return ( + } + > + } + authCallbackPage={false} + requireAuth + disableTelemetry + > + + + + ); +}; + +export const App = () => { + return ( + + + + ); +}; diff --git a/dev-console/src/apps/AppCreate.tsx b/dev-console/src/apps/AppCreate.tsx new file mode 100644 index 000000000..fc199b73b --- /dev/null +++ b/dev-console/src/apps/AppCreate.tsx @@ -0,0 +1,40 @@ +import { Form, SaveButton, SelectInput, TextInput } from 'react-admin'; +import { DialogActions, Stack } from '@mui/material'; +import { Page } from '../components/Page'; +import { schemaOAuthClient } from './schemas'; + +export const AppCreateForm = () => { + const types = schemaOAuthClient.properties?.applicationType['enum'] || [ + 'web', + ]; + + return ( +
+ + + + + ({ + id: t, + name: 'applicationType.' + t, + }))} + defaultValue={types[0]} + /> + + + + + +
+ ); +}; diff --git a/dev-console/src/apps/AppEdit.tsx b/dev-console/src/apps/AppEdit.tsx new file mode 100644 index 000000000..82482ebd2 --- /dev/null +++ b/dev-console/src/apps/AppEdit.tsx @@ -0,0 +1,284 @@ +import { Box } from '@mui/material'; +import { + AutocompleteArrayInput, + CheckboxGroupInput, + DeleteWithConfirmButton, + Edit, + Labeled, + List, + ReferenceArrayInput, + SaveButton, + ShowButton, + TabbedForm, + TextField, + TextInput, + Toolbar, + TopToolbar, + useDataProvider, + useEditContext, + useGetList, + useRecordContext, + useRefresh, +} from 'react-admin'; +import { JsonSchemaInput } from '@dslab/ra-jsonschema-input'; +import { InspectButton } from '@dslab/ra-inspect-button'; +import { SectionTitle } from '../components/SectionTitle'; +import { + claimMappingDefaultValue, + schemaOAuthClient, + schemaWebHooks, + uiSchemaOAuthClient, +} from './schemas'; +import { Page } from '../components/Page'; +import { AuthoritiesDialogButton } from '../components/AuthoritiesDialog'; +import { TestDialogButton } from './TestDialog'; +import { RefreshingExportButton } from '../components/RefreshingExportButton'; +import { IdpNameField } from '../idps/IdpList'; +import { AppResources } from './AppResources'; +import { AppTitle } from './AppShow'; +import { ClaimMappingEditor } from '../components/ClaimMappingEditor'; +import { useRootSelector } from '@dslab/ra-root-selector'; + +export const AppEdit = () => { + //fetch related to resolve relations + const { data: roles } = useGetList('roles', { + pagination: { page: 1, perPage: 100 }, + sort: { field: 'name', order: 'ASC' }, + }); + const { data: groups } = useGetList('groups', { + pagination: { page: 1, perPage: 100 }, + sort: { field: 'name', order: 'ASC' }, + }); + + //inflate back flattened fields + const transform = data => ({ + ...data, + roles: roles?.filter(r => data.roles.includes(r.id)), + groups: groups?.filter(r => data.groups.includes(r.id)), + }); + + return ( + + } + mutationMode="optimistic" + component={Box} + redirect={'edit'} + transform={transform} + queryOptions={{ meta: { flatten: ['roles', 'groups'] } }} + mutationOptions={{ meta: { flatten: ['roles', 'groups'] } }} + > + + + + + ); +}; + +const AppEditForm = () => { + const dataProvider = useDataProvider(); + const { root: realmId } = useRootSelector(); + + const { isLoading, record } = useEditContext(); + if (isLoading || !record) return null; + if (!record) return null; + + const handleTest = (record, code) => { + return dataProvider.invoke({ + path: 'apps/' + realmId + '/' + record.id + '/claims', + body: JSON.stringify({ + code, + name: 'claimMapping', + scopes: [], + }), + options: { + method: 'POST', + }, + }); + }; + + return ( + } syncWithLocation={false}> + + + + + + + + + + + + + + + + + + + + + + + + } + sx={{ textAlign: 'left' }} + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +const ActionsToolbar = () => { + const refresh = useRefresh(); + const record = useRecordContext(); + + if (!record) return null; + + return ( + + + + + refresh()} /> + + + + ); +}; + +const TabToolbar = () => ( + + + +); diff --git a/dev-console/src/apps/AppEndpoints.tsx b/dev-console/src/apps/AppEndpoints.tsx new file mode 100644 index 000000000..bfd463b19 --- /dev/null +++ b/dev-console/src/apps/AppEndpoints.tsx @@ -0,0 +1,81 @@ +import { useRootSelector } from '@dslab/ra-root-selector'; +import { + Container, + Stack, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, +} from '@mui/material'; +import { useState, useEffect } from 'react'; +import { + useDataProvider, + RecordContextProvider, + Labeled, + TextField, + useTranslate, +} from 'react-admin'; +import { IdField } from '../components/IdField'; + +export const AppEndpointsView = () => { + const dataProvider = useDataProvider(); + const translate = useTranslate(); + const { root: realmId } = useRootSelector(); + const [config, setConfig] = useState(); + + useEffect(() => { + dataProvider + .invoke({ path: 'realms/' + realmId + '/well-known/oauth2' }) + .then(data => { + if (data) { + setConfig(data); + } + }); + }, [dataProvider]); + + if (!config) return null; + + const fields = [ + 'issuer', + 'authorization_endpoint', + 'token_endpoint', + 'jwks_uri', + 'userinfo_endpoint', + 'introspection_endpoint', + 'revocation_endpoint', + 'registration_endpoint', + 'end_session_endpoint', + ]; + + return ( + + + + + {fields.map(field => ( + + + + {translate('field.' + field)} + + + + + + + ))} + +
+
+
+ ); +}; diff --git a/dev-console/src/apps/AppIcon.tsx b/dev-console/src/apps/AppIcon.tsx new file mode 100644 index 000000000..a8452f56b --- /dev/null +++ b/dev-console/src/apps/AppIcon.tsx @@ -0,0 +1,3 @@ +import GridViewIcon from '@mui/icons-material/GridView'; + +export const AppIcon = GridViewIcon; diff --git a/dev-console/src/apps/AppList.tsx b/dev-console/src/apps/AppList.tsx new file mode 100644 index 000000000..6d723a3b7 --- /dev/null +++ b/dev-console/src/apps/AppList.tsx @@ -0,0 +1,116 @@ +import { + List, + SearchInput, + Datagrid, + TopToolbar, + ExportButton, + useTranslate, + useRecordContext, +} from 'react-admin'; +import { YamlExporter } from '../components/YamlExporter'; +import { IdField } from '../components/IdField'; +import { PageTitle } from '../components/PageTitle'; +import { CreateInDialogButton } from '@dslab/ra-dialog-crud'; +import { AppCreateForm } from './AppCreate'; +import { ActionsButtons } from '../components/ActionsButtons'; +import { Box } from '@mui/material'; +import { Page } from '../components/Page'; +import { AppIcon } from './AppIcon'; +import { NameField } from '../components/NameField'; +import { isValidElement, ReactElement } from 'react'; +import { useRootSelector } from '@dslab/ra-root-selector'; +import { TagsField } from '../components/TagsField'; +import { getAppIcon } from './utils'; + +export const AppList = () => { + const translate = useTranslate(); + return ( + + + } + filters={ListFilters} + sort={{ field: 'name', order: 'DESC' }} + component={Box} + empty={false} + > + + + + ); +}; + +export const AppListView = (props: { actions?: ReactElement | boolean }) => { + const { actions: actionProps = true } = props; + + const actions = !actionProps ? ( + false + ) : isValidElement(actionProps) ? ( + actionProps + ) : ( + + ); + + return ( + + + + + {actions !== false && actions} + + ); +}; + +export const AppNameField = (props: { source: string; label?: string }) => { + const { label } = props; + const record = useRecordContext(); + + const icon = record ? ( + getAppIcon(record.configuration?.applicationType, { + color: 'primary', + }) + ) : ( + + ); + return ( + + ); +}; + +const ListFilters = []; + +const ListActions = () => { + const { root: realmId } = useRootSelector(); + const transform = (data: any) => { + return { + ...data, + realm: realmId, + type: 'oauth2', + }; + }; + + return ( + + + + + + + ); +}; diff --git a/dev-console/src/apps/AppResources.tsx b/dev-console/src/apps/AppResources.tsx new file mode 100644 index 000000000..70c384490 --- /dev/null +++ b/dev-console/src/apps/AppResources.tsx @@ -0,0 +1,149 @@ +import { + EditInDialogButton, + ShowInDialogButton, + useDialogContext, +} from '@dslab/ra-dialog-crud'; +import { + Stack, + Box, + Divider, + TableCell, + TableHead, + TableRow, + DialogActions, +} from '@mui/material'; +import { + Datagrid, + ArrayField, + SingleFieldList, + ChipField, + TextField, + DatagridHeaderProps, + FieldProps, + CheckboxGroupInput, + ReferenceArrayInput, + FunctionField, + WrapperField, + Form, + SaveButton, + Button, + useTranslate, + useResourceContext, + useInput, + useRecordContext, +} from 'react-admin'; +import { useWatch, ControllerRenderProps } from 'react-hook-form'; +import { IdField } from '../components/IdField'; +import { NameField } from '../components/NameField'; +import { Page } from '../components/Page'; +import React, { useMemo } from 'react'; +import ConfirmIcon from '@mui/icons-material/CheckCircle'; +import { DataGridBlankHeader } from '../components/DataGridBlankHeader'; + + +export const AppResources = () => { + const resource = useResourceContext(); + const { field } = useInput({ + resource, + source: 'scopes', + }); + + return ( + } + > + + + + +
+ + +
+
+ ); +}; +export const AppResourcesDialog = (props: { field: ControllerRenderProps }) => { + const { field } = props; + const translate = useTranslate(); + const { handleClose } = useDialogContext(); + const record = useRecordContext(); + + const defaultValue = useMemo(() => { + if (record) { + return field?.value?.filter(i => + record.scopes.map(s => s['id']).includes(i) + ); + } + return []; + }, [record]); + const selected = useWatch({ name: 'selected', defaultValue }); + + const handleUpdate = e => { + const scopes: any[] = []; + record?.scopes?.forEach(s => { + scopes.push({ id: s['id'], selected: selected.includes(s['id']) }); + }); + const value = [...field.value].filter( + v => scopes.find(s => v === s['id']) === undefined + ); + + value.push(...scopes.filter(s => s['selected']).map(s => s['id'])); + field.onChange(value); + + handleClose(e); + }; + + return ( + <> + + + + + + + + + } + tertiaryText="description" + source="name" + icon={false} + /> + } + sx={{ textAlign: 'left' }} + /> + + + + + +
+ + {translate(label)} + + + + +
+ + {isLoading ? ( + + ) : ( + + )} +
+ + ); +}; + +const TestEditDialog = (props: { + record: any; + resource: string; + handleClose: (e: any) => void; + onSuccess?: () => void; +}) => { + const { record, resource, handleClose, onSuccess } = props; + const translate = useTranslate(); + const dataProvider = useDataProvider(); + const notify = useNotify(); + const { root: realmId } = useRootSelector(); + const [flow, setFlow] = useState(); + const [isLoading, setIsLoading] = useState(false); + const [token, setToken] = useState({ + access_token: null, + access_token_decoded: null, + }); + + if (!record || !resource) return null; + if (isLoading) return ; + + const flows = record.configuration?.authorizedGrantTypes || []; + + const handleChange = e => { + setFlow(e.target.value); + }; + + const handleTest = e => { + if (flow) { + dataProvider + .invoke({ + path: + 'apps/' + realmId + '/' + record.id + '/oauth2/' + flow, + }) + .then(json => { + if (json) { + const t = { + ...json, + access_token_decoded: json.access_token?.includes( + '.' + ) + ? JSON.stringify( + JSON.parse( + atob(json.access_token.split('.')[1]) + ), + null, + 2 + ) + : null, + }; + setToken(t); + } else { + notify('ra.notification.bad_item', { type: 'warning' }); + } + }) + .catch(error => { + const msg = error.message || 'ra.notification.error'; + notify(msg, { type: 'error' }); + }); + } + }; + + return ( + + + + {translate('dialog.test.helperText')} + + + {translate('oauth2.flows.title')} + + + {flow && ( + + + + + + {translate( + 'oauth2.flows.' + flow + '.name' + )} + + + {flow} + + + {translate( + 'oauth2.flows.' + + flow + + '.description' + )} + + + + + + )} + {!record.enabled && ( + + )} + + ); +}; diff --git a/dev-console/src/aps/ApIcon.tsx b/dev-console/src/aps/ApIcon.tsx new file mode 100644 index 000000000..56b9f2a6d --- /dev/null +++ b/dev-console/src/aps/ApIcon.tsx @@ -0,0 +1,2 @@ +import FactCheckIcon from '@mui/icons-material/FactCheck'; +export const ApIcon = FactCheckIcon; diff --git a/dev-console/src/aps/ApList.tsx b/dev-console/src/aps/ApList.tsx new file mode 100644 index 000000000..309ac5e47 --- /dev/null +++ b/dev-console/src/aps/ApList.tsx @@ -0,0 +1,158 @@ +import { Box } from '@mui/material'; + +import { isValidElement, ReactElement } from 'react'; +import { + Datagrid, + List, + SearchInput, + TopToolbar, + useRecordContext, + ExportButton, + useTranslate, + BooleanField, + FunctionField, +} from 'react-admin'; +import { YamlExporter } from '../components/YamlExporter'; +import { useRootSelector } from '@dslab/ra-root-selector'; +import { ApCreateForm } from './ApCreate'; +import { CreateInDialogButton } from '@dslab/ra-dialog-crud'; +import { ActionsButtons } from '../components/ActionsButtons'; +import { IdField } from '../components/IdField'; +import { PageTitle } from '../components/PageTitle'; +import { Page } from '../components/Page'; +import { NameField } from '../components/NameField'; +import { ApIcon } from './ApIcon'; +import { getApIcon } from './utils'; +import EnabledIcon from '@mui/icons-material/CheckCircleOutlined'; +import DisabledIcon from '@mui/icons-material/CancelOutlined'; +import RegisteredIcon from '@mui/icons-material/VerifiedUser'; +import WarningIcon from '@mui/icons-material/WarningOutlined'; + +export const ApList = () => { + const translate = useTranslate(); + return ( + + + } + filters={ListFilters} + sort={{ field: 'name', order: 'ASC' }} + component={Box} + empty={false} + > + + + + ); +}; + +export const ApListView = (props: { actions?: ReactElement | boolean }) => { + const { actions: actionProps = true } = props; + + const actions = !actionProps ? ( + false + ) : isValidElement(actionProps) ? ( + actionProps + ) : ( + + ); + + return ( + + + + + + { + if (!record.enabled) return <>; + return ( + + ); + }} + /> + {actions !== false && actions} + + ); +}; + +export const ApNameField = (props: { source: string; label?: string }) => { + const { label } = props; + const record = useRecordContext(); + const color = record?.registered + ? 'primary' + : record?.enabled + ? 'warning' + : 'info'; + + const iconColor = record?.registered + ? 'primary' + : record?.enabled + ? 'error' + : 'disabled'; + + const icon = record ? ( + getApIcon(record.authority, { + color: iconColor, + }) + ) : ( + + ); + + return ( + + ); +}; + +const ListFilters = []; + +const ListActions = () => { + const { root: realmId } = useRootSelector(); + const transform = (data: any) => { + return { + ...data, + type: 'attributes', + realm: realmId, + }; + }; + + return ( + + + + + + + ); +}; diff --git a/dev-console/src/aps/index.tsx b/dev-console/src/aps/index.tsx new file mode 100644 index 000000000..d777cb397 --- /dev/null +++ b/dev-console/src/aps/index.tsx @@ -0,0 +1,11 @@ +import { ApEdit } from './ApEdit'; +import { ApIcon } from './ApIcon'; +import { ApList } from './ApList'; + +export default { + name: 'aps', + list: ApList, + edit: ApEdit, + icon: ApIcon, + recordRepresentation: record => record.name, +}; diff --git a/dev-console/src/aps/schemas.ts b/dev-console/src/aps/schemas.ts new file mode 100644 index 000000000..94050d1fc --- /dev/null +++ b/dev-console/src/aps/schemas.ts @@ -0,0 +1,125 @@ +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +export const getApSchema = (schema?: any) => { + if (!schema) { + return {}; + } + + //fix id definition + //TODO update in backend + if ('id' in schema) { + schema['$id'] = schema['id']; + delete schema['id']; + } + + //fix definition + if ( + schema['$id'] === + 'urn:jsonschema:it:smartcommunitylab:aac:attributes:provider:MapperAttributeProviderConfigMap' + ) { + schema['properties']['type']['enum'] = ['default', 'exact']; + } + + return schema; +}; + +export const getApUiSchema = (schema?: any) => { + if (!schema || (!('$id' in schema) && !('id' in schema))) { + return {}; + } + + const type = schema['$id'] || schema['id']; + let uiSchema = {}; + if (type in idpUiSchemas) { + uiSchema = { ...idpUiSchemas[type] }; + } + + //inject titles if missing + if (schema) { + for (const p in schema.properties) { + if (!(p in uiSchema)) { + uiSchema[p] = {}; + } + + if (!('ui:title' in uiSchema[p])) { + uiSchema[p]['ui:title'] = + schema.properties[p].title || 'field.' + p + '.name'; + } + if (!('ui:description' in uiSchema[p])) { + uiSchema[p]['ui:description'] = + schema.properties[p].description || + 'field.' + p + '.helperText'; + } + } + } + + return uiSchema; +}; + +export const schemaApSettings: RJSFSchema = { + type: 'object', + properties: { + events: { + type: 'string', + enum: ['none', 'minimal', 'details', 'full'], + default: 'minimal', + title: 'field.events.name', + description: 'field.events.helperText', + }, + persistence: { + type: 'string', + enum: ['none', 'repository', 'session'], + default: 'repository', + title: 'field.persistence.name', + description: 'field.persistence.helperText', + }, + notes: { + type: 'string', + title: 'field.notes.name', + description: 'field.notes.helperText', + }, + }, +}; + +export const uiSchemaApSettings: UiSchema = { + 'ui:layout': [12], +}; + +export const uiSchemaInternalAp: UiSchema = { + 'ui:layout': [4, 4, 4], + 'ui:order': [ + 'enableRegistration', + 'enableDelete', + 'enableUpdate', + 'maxSessionDuration', + 'confirmationRequired', + 'confirmationValidity', + ], +}; +export const uiSchemaScriptAp: UiSchema = { + code: { + 'ui:widget': 'hidden', + }, +}; +//list + +export const idpUiSchemas = { + 'urn:jsonschema:it:smartcommunitylab:aac:attributes:provider:ScriptAttributeProviderConfigMap': + uiSchemaScriptAp, + // 'urn:jsonschema:it:smartcommunitylab:aac:internal:provider:InternalIdentityProviderConfigMap': + // uiSchemaInternalIdp, + // 'urn:jsonschema:it:smartcommunitylab:aac:password:provider:PasswordIdentityProviderConfigMap': + // uiSchemaPasswordIdp, + // 'urn:jsonschema:it:smartcommunitylab:aac:oidc:apple:provider:AppleIdentityProviderConfigMap': + // uiSchemaAppleIdp, + // 'urn:jsonschema:it:smartcommunitylab:aac:oidc:provider:OIDCIdentityProviderConfigMap': + // uiSchemaOidcIdp, + // 'urn:jsonschema:it:smartcommunitylab:aac:openidfed:provider:OpenIdFedIdentityProviderConfigMap': + // uiSchemaOpenidfedIdp, + // 'urn:jsonschema:it:smartcommunitylab:aac:webauthn:provider:WebAuthnIdentityProviderConfigMap': + // uiSchemaWebAuthnIdp, + // 'urn:jsonschema:it:smartcommunitylab:aac:saml:provider:SamlIdentityProviderConfigMap': + // uiSchemaSamlIdp, + // 'urn:jsonschema:it:smartcommunitylab:aac:spid:provider:SpidIdentityProviderConfigMap': + // uiSchemaSpidIdp, +}; diff --git a/dev-console/src/aps/utils.tsx b/dev-console/src/aps/utils.tsx new file mode 100644 index 000000000..879b93dfb --- /dev/null +++ b/dev-console/src/aps/utils.tsx @@ -0,0 +1,31 @@ +import React from 'react'; + +import { ApIcon } from './ApIcon'; +import LockPersonIcon from '@mui/icons-material/LockPerson'; +import CloudSyncIcon from '@mui/icons-material/CloudSync'; +import FolderSharedIcon from '@mui/icons-material/FolderShared'; +import TerminalIcon from '@mui/icons-material/Terminal'; +import RouteIcon from '@mui/icons-material/Route'; + +import { SvgIconOwnProps } from '@mui/material'; + +export const InternalApIcon = LockPersonIcon; + +export const authorities = { + internal: { icon: FolderSharedIcon }, + mapper: { icon: RouteIcon }, + script: { icon: TerminalIcon }, + webhook: { icon: CloudSyncIcon }, +}; + +export const getApIcon = (authority?: string, props?: SvgIconOwnProps) => { + if (!authority) { + return ; + } + + if (authority in authorities) { + return React.createElement(authorities[authority].icon, props); + } + + return ; +}; diff --git a/dev-console/src/attributeset/AttributeSetCreate.tsx b/dev-console/src/attributeset/AttributeSetCreate.tsx new file mode 100644 index 000000000..6df528e49 --- /dev/null +++ b/dev-console/src/attributeset/AttributeSetCreate.tsx @@ -0,0 +1,50 @@ +import { + Form, + regex, + required, + SaveButton, + TextInput, + useTranslate, +} from 'react-admin'; +import { DialogActions, Stack } from '@mui/material'; +import { Page } from '../components/Page'; + +const pattern = /^[a-zA-Z.:_-]{3,}$/; + +export const AttributeSetCreateForm = () => { + const translate = useTranslate(); + + return ( +
+ + + + + + + + + +
+ ); +}; diff --git a/dev-console/src/attributeset/AttributeSetEdit.tsx b/dev-console/src/attributeset/AttributeSetEdit.tsx new file mode 100644 index 000000000..af36270d9 --- /dev/null +++ b/dev-console/src/attributeset/AttributeSetEdit.tsx @@ -0,0 +1,191 @@ +import { Box, Chip, Stack } from '@mui/material'; +import { + ArrayInput, + BooleanInput, + Edit, + Labeled, + regex, + required, + SaveButton, + SelectInput, + SimpleFormIterator, + TabbedForm, + TextField, + TextInput, + Toolbar, + TopToolbar, + useRecordContext, + useTranslate, + WrapperField, +} from 'react-admin'; +import { InspectButton } from '@dslab/ra-inspect-button'; +import { DeleteWithDialogButton } from '@dslab/ra-delete-dialog-button'; +import { Page } from '../components/Page'; +import { SectionTitle } from '../components/SectionTitle'; +import { RefreshingExportButton } from '../components/RefreshingExportButton'; +import { ResourceTitle } from '../components/ResourceTitle'; + +const pattern = /^[a-zA-Z.:_-]{3,}$/; + +export const AttributeSetEdit = () => { + return ( + + } + mutationMode="optimistic" + component={Box} + redirect={'edit'} + > + + + + + ); +}; + +const AttributeSetEditForm = () => { + const translate = useTranslate(); + const record = useRecordContext(); + if (!record) return null; + + return ( + } syncWithLocation={false}> + + + + + + + + + + + + + + {record?.keys?.map(k => ( + + ))} + + + + + + + + + + + + {record?.identifier && !record.identifier.startsWith('aac') && ( + + + + + + + + + + + + + + )} + + ); +}; + +const ActionsToolbar = () => { + const record = useRecordContext(); + if (!record) return null; + + return ( + + + + + + ); +}; + +const TabToolbar = () => ( + + + +); diff --git a/dev-console/src/attributeset/AttributeSetIcon.tsx b/dev-console/src/attributeset/AttributeSetIcon.tsx new file mode 100644 index 000000000..42443598c --- /dev/null +++ b/dev-console/src/attributeset/AttributeSetIcon.tsx @@ -0,0 +1,3 @@ +import InventoryIcon from '@mui/icons-material/Inventory'; + +export const AttributeSetIcon = InventoryIcon; diff --git a/dev-console/src/attributeset/AttributeSetList.tsx b/dev-console/src/attributeset/AttributeSetList.tsx new file mode 100644 index 000000000..44489d0d2 --- /dev/null +++ b/dev-console/src/attributeset/AttributeSetList.tsx @@ -0,0 +1,98 @@ +import { + List, + SearchInput, + Datagrid, + TopToolbar, + useTranslate, + ExportButton, +} from 'react-admin'; +import { Box } from '@mui/material'; +import { YamlExporter } from '../components/YamlExporter'; + +import { isValidElement, ReactElement } from 'react'; +import { useRootSelector } from '@dslab/ra-root-selector'; +import { CreateInDialogButton } from '@dslab/ra-dialog-crud'; +import { PageTitle } from '../components/PageTitle'; +import { ActionsButtons } from '../components/ActionsButtons'; +import { IdField } from '../components/IdField'; +import { NameField } from '../components/NameField'; +import { Page } from '../components/Page'; +import { AttributeSetIcon } from './AttributeSetIcon'; +import { AttributeSetCreateForm } from './AttributeSetCreate'; + +export const AttributeSetList = () => { + const translate = useTranslate(); + return ( + + + } + filters={AttributeSetFilters} + sort={{ field: 'name', order: 'ASC' }} + component={Box} + empty={false} + filter={{ system: true }} + > + + + + ); +}; + +export const AttributeSetListView = (props: { + actions?: ReactElement | boolean; +}) => { + const { actions: actionProps = true } = props; + + const actions = !actionProps ? ( + false + ) : isValidElement(actionProps) ? ( + actionProps + ) : ( + + ); + + return ( + + } + /> + + {actions !== false && actions} + + ); +}; + +const AttributeSetFilters = []; + +const AttributeSetListActions = () => { + const { root: realmId } = useRootSelector(); + const transform = (data: any) => { + return { + ...data, + realm: realmId, + }; + }; + + return ( + + + + + + + ); +}; diff --git a/dev-console/src/attributeset/index.tsx b/dev-console/src/attributeset/index.tsx new file mode 100644 index 000000000..a940fbe64 --- /dev/null +++ b/dev-console/src/attributeset/index.tsx @@ -0,0 +1,11 @@ +import { AttributeSetIcon } from './AttributeSetIcon'; +import { AttributeSetEdit } from './AttributeSetEdit'; +import { AttributeSetList } from './AttributeSetList'; + +export default { + name: 'attributeset', + list: AttributeSetList, + edit: AttributeSetEdit, + icon: AttributeSetIcon, + recordRepresentation: record => record.name, +}; diff --git a/dev-console/src/audit/AuditDetails.tsx b/dev-console/src/audit/AuditDetails.tsx new file mode 100644 index 000000000..2b59a9934 --- /dev/null +++ b/dev-console/src/audit/AuditDetails.tsx @@ -0,0 +1,93 @@ +import { + TextField, + useRecordContext, + LinearProgress, + Labeled, + DateField, + FieldTitle, +} from 'react-admin'; +import { Box, Typography, Stack, Grid, Chip } from '@mui/material'; + +export const AuditDetails = () => { + const record = useRecordContext(); + if (!record || !record.data) { + return ; + } + return ; +}; + +const UserAuthAuditDetails = () => { + const record: any = useRecordContext(); + if (!record || !record.data) { + return
; + } + + return ( + + + + new Date(value * 1000)} + /> + + + + + + + + + + + + {record.data && ( + + {record.data.provider && ( + + + + )} + {record.data.authority && ( + + + + )} + {record.data.details && + record.data.details.remoteAddress && ( + + + + )} + {record.data.details && record.data.details.protocol && ( + + + + )} + {record.data.details && record.data.details.userAgent && ( + + + + )} + + )} + + ); +}; \ No newline at end of file diff --git a/dev-console/src/audit/AuditIcon.tsx b/dev-console/src/audit/AuditIcon.tsx new file mode 100644 index 000000000..81b0a6636 --- /dev/null +++ b/dev-console/src/audit/AuditIcon.tsx @@ -0,0 +1,4 @@ +import EventNoteIcon from '@mui/icons-material/EventNote'; +import DocumentScannerOutlinedIcon from '@mui/icons-material/DocumentScannerOutlined'; + +export const AuditIcon = DocumentScannerOutlinedIcon; diff --git a/dev-console/src/audit/AuditList.tsx b/dev-console/src/audit/AuditList.tsx new file mode 100644 index 000000000..659e23fd0 --- /dev/null +++ b/dev-console/src/audit/AuditList.tsx @@ -0,0 +1,180 @@ +import { + List, + useListContext, + SearchInput, + Datagrid, + TextField, + DateField, + TopToolbar, + DateInput, + SelectInput, + useTranslate, +} from 'react-admin'; +import { useParams } from 'react-router-dom'; +import ContentFilter from '@mui/icons-material/FilterList'; +import { AuditDetails } from './AuditDetails'; +import { Typography } from '@mui/material'; + +import { useForm, FormProvider } from 'react-hook-form'; +import { Box, Button } from '@mui/material'; +import { Page } from '../components/Page'; +import { PageTitle } from '../components/PageTitle'; +import { YamlExporter } from '../components/YamlExporter'; +import { InspectButton } from '@dslab/ra-inspect-button'; + +export const AuditList = () => { + const translate = useTranslate(); + useListContext(); + return ( + + + } + empty={false} + exporter={YamlExporter} + filters={AuditFilters} + sort={{ field: 'time', order: 'DESC' }} + component={Box} + > + + + + ); +}; + +export const AuditListView = () => { + return ( + } + bulkActionButtons={false} + expandSingle + > + + + + <> + + + + ); +}; + +const AuditFilters = []; + +// https://marmelab.com/react-admin/FilteringTutorial.html#building-a-custom-filter +const PostFilterButton = () => { + const { showFilter } = useListContext(); + return ( + + ); +}; + +const PostFilterForm = () => { + const { displayedFilters, filterValues, setFilters, hideFilter } = + useListContext(); + + const form = useForm({ + defaultValues: filterValues, + }); + + if (!displayedFilters.main) return null; + + const onSubmit = (values: any) => { + if (Object.keys(values).length > 0) { + if (values.before) { + let before = new Date(values.before); + values.before = before.toISOString(); + } + if (values.after) { + let after = new Date(values.after); + values.after = after.toISOString(); + } + if (values.type == 'All') { + values.type = null; + } + setFilters(values, null); + } else { + hideFilter('main'); + } + }; + + const resetFilter = () => { + setFilters({}, []); + }; + + return ( + +
+ + + + + + + + + + + + + + + + + +
+
+ ); +}; + +const ListActions = () => ( + + + + + + +); diff --git a/dev-console/src/audit/index.tsx b/dev-console/src/audit/index.tsx new file mode 100644 index 000000000..dbcdd5fd8 --- /dev/null +++ b/dev-console/src/audit/index.tsx @@ -0,0 +1,9 @@ +import { AuditIcon } from './AuditIcon'; +import { AuditList } from './AuditList'; + +export default { + name: 'audit', + list: AuditList, + // icon: AuditIcon, + recordRepresentation: record => record.id, +}; diff --git a/dev-console/src/authProvider.ts b/dev-console/src/authProvider.ts new file mode 100644 index 000000000..30c958a44 --- /dev/null +++ b/dev-console/src/authProvider.ts @@ -0,0 +1,72 @@ +import { AuthProvider, fetchUtils, Options } from 'react-admin'; + +const fetchJson = (url: string, options: Options = {}) => { + if (!options.headers) { + options.headers = new Headers({ Accept: 'application/json' }); + } + + options.credentials = 'include'; + + return fetchUtils.fetchJson(url, options); +}; + +export default (baseUrl: string, httpClient = fetchJson): AuthProvider => { + const apiUrl = baseUrl + '/console/user'; + + return { + login: async (params: any) => {}, + logout: async (params: any) => { + window.location.href = `${baseUrl}/logout`; + return; + }, + checkError: async (error: any) => { + const status = error.status; + if (status === 401 || status === 403) { + return Promise.reject(); + } + // other error code (404, 500, etc): no need to log out + return Promise.resolve(); + }, + checkAuth: async (params: any) => { + const url = `${apiUrl}/status`; + const { status } = await httpClient(url); + if (status !== 200) { + throw new Error('unauthorized'); + } + }, + getIdentity: async () => { + //load from profile + let url = `${apiUrl}/me`; + const { status, json } = await httpClient(url); + + if (status !== 200 || !json || !json.subjectId) { + throw new Error('profile error'); + } + + //explode realm model + url = `${apiUrl}/realm`; + const { status: rstatus, json: rjson } = await httpClient(url); + + if (rstatus !== 200 || !rjson || !rjson.slug) { + throw new Error('profile error'); + } + + return { + id: json.subjectId, + fullName: json.username, + ...json, + realm: rjson, + }; + }, + getPermissions: async () => { + //load from authorities + const url = `${apiUrl}/authorities`; + const { status, json } = await httpClient(url); + if (status !== 200 || !json) { + throw new Error('permissions error'); + } + + return json; + }, + }; +}; diff --git a/dev-console/src/components/ActionsButtons.tsx b/dev-console/src/components/ActionsButtons.tsx new file mode 100644 index 000000000..16da8e843 --- /dev/null +++ b/dev-console/src/components/ActionsButtons.tsx @@ -0,0 +1,30 @@ +import { + EditButton, + ShowButton, + useRecordContext, + useResourceContext, + useResourceDefinition, +} from 'react-admin'; +import { DeleteWithDialogButton } from '@dslab/ra-delete-dialog-button'; +import { DropDownButton } from './DropdownButton'; +import { RowButtonGroup } from './RowButtonGroup'; + +export const ActionsButtons = () => { + const record = useRecordContext(); + const resource = useResourceContext(); + const definition = useResourceDefinition(); + + if (!record) { + return null; + } + + return ( + + + {definition?.hasShow && } + {definition?.hasEdit && } + + + + ); +}; diff --git a/dev-console/src/components/AuthoritiesDialog.tsx b/dev-console/src/components/AuthoritiesDialog.tsx new file mode 100644 index 000000000..d716a0aed --- /dev/null +++ b/dev-console/src/components/AuthoritiesDialog.tsx @@ -0,0 +1,332 @@ +import { + Box, + Breakpoint, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Divider, + FormControl, + FormGroup, + FormLabel, + Grid, + IconButton, + Stack, + styled, + Switch, + Typography, +} from '@mui/material'; +import { + Fragment, + ReactElement, + useCallback, + useEffect, + useState, +} from 'react'; +import { + RaRecord, + ButtonProps, + useRecordContext, + useResourceContext, + useTranslate, + Button, + LoadingIndicator, + useDataProvider, + useNotify, +} from 'react-admin'; +import { useRootSelector } from '@dslab/ra-root-selector'; + +import LocalPoliceIcon from '@mui/icons-material/LocalPolice'; +import CloseIcon from '@mui/icons-material/Close'; +import CancelIcon from '@mui/icons-material/ErrorOutline'; +import ConfirmIcon from '@mui/icons-material/CheckCircle'; + +const defaultIcon = ; +export const AuthoritiesIcon = LocalPoliceIcon; + +export const AuthoritiesDialogButton = ( + props: AuthoritiesDialogButtonProps +) => { + const { + label = 'action.authorities', + icon = defaultIcon, + fullWidth = true, + maxWidth = 'sm', + color = 'warning', + record: recordFromProps, + resource: resourceFromProps, + onSuccess, + ...rest + } = props; + const translate = useTranslate(); + const [open, setOpen] = useState(false); + + const resourceContext = useResourceContext(); + const recordContext = useRecordContext(); + + const resource = resourceFromProps || resourceContext; + const record = recordFromProps || recordContext; + const isLoading = !record; + + const handleDialogOpen = e => { + setOpen(true); + e.stopPropagation(); + }; + + const handleDialogClose = e => { + setOpen(false); + e.stopPropagation(); + }; + const handleClick = useCallback(e => { + e.stopPropagation(); + }, []); + + return ( + + + +
+ + {translate(label)} + + + + +
+ + {isLoading ? ( + + ) : ( + + )} +
+
+ ); +}; + +const AuthoritiesEditDialog = (props: { + record: any; + resource: string; + handleClose: (e: any) => void; + onSuccess?: () => void; +}) => { + const { record, resource, handleClose, onSuccess } = props; + const translate = useTranslate(); + const dataProvider = useDataProvider(); + const notify = useNotify(); + const { root: realmId } = useRootSelector(); + const [authorities, setAuthorities] = useState([]); + const [isLoading, setIsLoading] = useState(true); + //hard-coded + const roles = ['ROLE_DEVELOPER', 'ROLE_ADMIN']; + + useEffect(() => { + if (record) { + dataProvider + .invoke({ + path: + resource + + '/' + + realmId + + '/' + + record.id + + '/authorities', + }) + .then(data => { + if (data) { + setAuthorities(data); + } + }); + } + return () => { + setIsLoading(false); + }; + }, [dataProvider, record]); + + const handleSwitch = role => { + return (event: React.ChangeEvent) => { + setAuthorities(list => { + const keep = list.filter(e => e.role !== role); + const edit = event.target.checked + ? [{ realm: realmId, role: role }] + : []; + return [...keep, ...edit]; + }); + }; + }; + + const handleSave = e => { + dataProvider + .invoke({ + path: + resource + '/' + realmId + '/' + record.id + '/authorities', + body: JSON.stringify(authorities), + options: { + method: 'PUT', + }, + }) + .then(() => { + notify('ra.notification.updated'); + if (onSuccess) { + onSuccess(); + } + }); + + handleClose(e); + }; + + if (!record || !resource) return null; + if (isLoading) return ; + + return ( + <> + + + + {translate('dialog.authorities.helperText')} + + + {roles.map(r => { + const checked = + authorities.find(a => a.role === r) || false; + + return ( + + + + + + {translate( + 'authorities.' + + r + + '.name' + )} + + + {r} + + + {translate( + 'authorities.' + + r + + '.description' + )} + + + + + + + + + + ); + })} + + + + + +
+ + + {children} + + + + ); +}; + +export type DrodownButtonProps = + ShowButtonProps & { + children: ReactElement | ReactElement[]; + }; diff --git a/dev-console/src/components/GridList.tsx b/dev-console/src/components/GridList.tsx new file mode 100644 index 000000000..16ec496c6 --- /dev/null +++ b/dev-console/src/components/GridList.tsx @@ -0,0 +1,138 @@ +import { Box, Grid } from '@mui/material'; +import { + useListContext, + RecordContextProvider, + SimpleListProps, + RaRecord, + useTranslate, + Identifier, +} from 'react-admin'; +import LinearProgress from '@mui/material/LinearProgress'; +import { Card, CardContent, CardActions, CardHeader } from '@mui/material'; +import { isValidElement, ReactElement, ReactNode } from 'react'; + +// const style = { +// // Use flex layout with column direction for components in the card +// // (CardContent and CardActions) +// display: 'flex', +// flexDirection: 'column', + +// // Justify the content so that CardContent will always be at the top of the card, +// // and CardActions will be at the bottom +// justifyContent: 'space-between', +// }; + +export const GridList = ( + props: GridListProps +) => { + const { cols = 6 } = props; + const { primaryText, secondaryText, tertiaryText, icon, actions } = props; + + const { data, isLoading } = useListContext(props); + // const resource = useResourceContext(props); + const translate = useTranslate(); + + if (isLoading === true) { + return ; + } + + if (!data) return null; + + return ( + + + {data.map((record, rowIndex) => ( + + + + {!!primaryText && + (isValidElement(primaryText) ? ( + primaryText + ) : ( + + ))} + + {secondaryText && + (typeof secondaryText === 'string' + ? translate(secondaryText, { + ...record, + _: secondaryText, + }) + : isValidElement(secondaryText) + ? secondaryText + : secondaryText(record, record.id))} + + {actions && ( + + {isValidElement(actions) + ? actions + : actions(record, record.id)} + + )} + + + + ))} + + + ); +}; + +export type FunctionToElement = ( + record: RecordType, + id: Identifier +) => ReactNode; + +export interface GridListProps + extends SimpleListProps { + cols?: number; + icon?: FunctionToElement | ReactElement; + tertiaryText?: FunctionToElement | string; + actions?: FunctionToElement | ReactElement; +} +export default GridList; diff --git a/dev-console/src/components/IdField.tsx b/dev-console/src/components/IdField.tsx new file mode 100644 index 000000000..4ad3c3a72 --- /dev/null +++ b/dev-console/src/components/IdField.tsx @@ -0,0 +1,78 @@ +import { Stack, Typography } from '@mui/material'; +import get from 'lodash/get'; +import { MouseEvent } from 'react'; + +import { + TextFieldProps, + useRecordContext, + sanitizeFieldRestProps, + useNotify, + IconButtonWithTooltip, + useTranslate, +} from 'react-admin'; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import { grey } from '@mui/material/colors'; + +export const IdField = < + RecordType extends Record = Record +>( + props: TextFieldProps & { + copy?: boolean; + format?: (value: any) => any; + } +) => { + const { + className, + source, + emptyText, + copy = true, + format = v => v, + label, + ...rest + } = props; + const record = useRecordContext(props); + const notify = useNotify(); + const translate = useTranslate(); + + const value = get(record, source); + if (!value) return null; + + const displayValue = format(value); + const displayLabel = + label && typeof label === 'string' + ? translate(label) + : source && typeof source === 'string' + ? translate(source) + : translate('content'); + + return ( + + + {displayValue} + + {copy && ( + ) => { + event.stopPropagation(); + if (value) { + navigator.clipboard.writeText(value); + notify('message.content_copied_x', { + messageArgs: { x: displayLabel }, + }); + } + }} + > + + + )} + + ); +}; diff --git a/dev-console/src/components/JsonSchemaFormInput.tsx b/dev-console/src/components/JsonSchemaFormInput.tsx new file mode 100644 index 000000000..3aaac06f1 --- /dev/null +++ b/dev-console/src/components/JsonSchemaFormInput.tsx @@ -0,0 +1,113 @@ +import { + useInput, + useTranslate, + useTranslateLabel, + InputProps, +} from 'react-admin'; +import validator from '@rjsf/validator-ajv8'; +import { RJSFSchema, UiSchema, GenericObjectType } from '@rjsf/utils'; +import { Form } from '@rjsf/mui'; + +export const JsonSchemaFormInput = (props: JSONSchemaFormatInputProps) => { + const { + schema, + uiSchema = {}, + label, + helperText, + resource, + source, + onBlur, + onChange, + } = props; + const { + field, + fieldState: { isTouched, error }, + formState: { isSubmitted }, + } = useInput({ + onChange, + onBlur, + ...props, + }); + const translate = useTranslate(); + const translateLabel = useTranslateLabel(); + + const update = (data: any) => { + field.onChange(data); + }; + + const rjschema: RJSFSchema = + typeof schema === 'string' + ? JSON.parse(schema) + : (schema as RJSFSchema); + + const ruischema: UiSchema = + typeof uiSchema === 'string' + ? JSON.parse(uiSchema) + : (uiSchema as UiSchema); + + //auto-add values from translation to uiSchema if missing + const ui: GenericObjectType = ruischema as GenericObjectType; + if (label && !('ui:title' in ui)) { + ui['ui:title'] = + typeof label === 'string' + ? translate(label) + : typeof label === 'boolean' + ? translate(source) + : ''; + } + if (helperText && !('ui:description' in ui)) { + ui['ui:description'] = + typeof helperText === 'string' ? translate(helperText) : ''; + } + + //auto-enrich schema with titles from key when missing + if (rjschema && 'properties' in rjschema) { + for (const k in rjschema.properties) { + const p: GenericObjectType = rjschema.properties[ + k + ] as GenericObjectType; + if (!('title' in p)) { + p.title = k; + } + if (ui) { + if (!(k in ui)) { + ui[k] = {}; + } + + if (!('ui:title' in ui[k])) { + //auto generate key and translate + ui[k]['ui:title'] = translateLabel({ + source: source + '.' + k, + resource: resource, + }); + } else { + //translate user-provided + ui[k]['ui:title'] = translate(ui[k]['ui:title']); + } + } + } + } + + return ( +
update(e.formData)} + omitExtraData={true} + liveValidate={true} + showErrorList={false} + > + <> +
+ ); +}; + +export type JSONSchemaFormatInputProps = InputProps & { + schema: RJSFSchema | object | string; + uiSchema?: UiSchema | object | string; +}; + +export default JsonSchemaFormInput; diff --git a/dev-console/src/components/NameField.tsx b/dev-console/src/components/NameField.tsx new file mode 100644 index 000000000..b54006139 --- /dev/null +++ b/dev-console/src/components/NameField.tsx @@ -0,0 +1,69 @@ +import { Stack, Avatar, TypographyOwnProps } from '@mui/material'; +import { grey } from '@mui/material/colors'; +import { FieldProps, TextField, useRecordContext } from 'react-admin'; +import { isValidElement, ReactElement } from 'react'; +import get from 'lodash/get'; + +export const NameField = (props: NameFieldProps) => { + const { + text, + secondaryText, + tertiaryText, + icon, + color = 'primary', + } = props; + const record = useRecordContext(props); + const displayText = typeof text === 'string' ? get(record, text) || '' : ''; + + return ( + + {icon !== false && ( + + {icon && isValidElement(icon) + ? icon + : displayText.substring(0, 2)} + + )} + + + + {secondaryText && ( + + )} + + {tertiaryText && ( + + )} + + + ); +}; + +export const OptionalTextField = ( + props: { + text: string | ReactElement; + } & Pick +) => { + const { text, variant, color } = props; + if (!text) return <>; + + return typeof text === 'string' ? ( + + ) : isValidElement(text) ? ( + text + ) : ( + <> + ); +}; + +export interface NameFieldProps + extends FieldProps, + Pick { + //text is either a field name or an element + text: string | ReactElement; + //text is either a field name or an element + secondaryText?: string | ReactElement; + //text is either a field name or an element + tertiaryText?: string | ReactElement; + icon?: ReactElement | boolean; +} diff --git a/dev-console/src/components/Page.tsx b/dev-console/src/components/Page.tsx new file mode 100644 index 000000000..0ccbe6a33 --- /dev/null +++ b/dev-console/src/components/Page.tsx @@ -0,0 +1,31 @@ +import { styled } from '@mui/material/styles'; +import { Container, ContainerOwnProps, Paper, PaperProps } from '@mui/material'; + +export const Page = ( + props: PaperProps & Pick +) => { + const { + children, + className, + elevation = 0, + maxWidth = false, + ...rest + } = props; + + return ( + + + {children} + + + ); +}; + +const StyledPaper = styled(Paper, { + name: 'ContainerPaper', +})(({ theme }) => ({ + padding: theme.spacing(3), + // flex: 1, + // display: 'flex', + // backgroundColor: theme.palette.grey[100], +})); diff --git a/dev-console/src/components/PageTitle.tsx b/dev-console/src/components/PageTitle.tsx new file mode 100644 index 000000000..0fb4ec831 --- /dev/null +++ b/dev-console/src/components/PageTitle.tsx @@ -0,0 +1,85 @@ +import { + Typography, + Paper, + Container, + Box, + IconButton, + Stack, +} from '@mui/material'; +import { isValidElement, ReactElement } from 'react'; +import { + IconButtonWithTooltip, + sanitizeFieldRestProps, + useNotify, +} from 'react-admin'; +import { MouseEvent } from 'react'; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import { grey } from '@mui/material/colors'; + +export const PageTitle = (props: PageTitleProps) => { + const { text, secondaryText, copy, icon } = props; + const notify = useNotify(); + + return ( + + + {icon && isValidElement(icon) ? icon : ''} + + {text && isValidElement(text) ? ( + text + ) : ( + + {text} + + )} + {secondaryText && ( + <> + + {secondaryText} + + {copy && ( + + ) => { + event.stopPropagation(); + if (secondaryText) { + navigator.clipboard.writeText( + secondaryText + ); + notify('message.content_copied'); + } + }} + > + + + )} + + )} + + + + ); +}; + +export interface PageTitleProps { + text: string | ReactElement; + secondaryText?: any; + copy?: boolean; + icon?: ReactElement; +} diff --git a/dev-console/src/components/ReferencedArrayInput.tsx b/dev-console/src/components/ReferencedArrayInput.tsx new file mode 100644 index 000000000..b32da81a8 --- /dev/null +++ b/dev-console/src/components/ReferencedArrayInput.tsx @@ -0,0 +1,97 @@ +import { + AutocompleteArrayInput, + Button, + ReferenceArrayInput, + Toolbar, + useDataProvider, + useGetList, + useNotify, + useRecordContext, + useRefresh, + useResourceContext, +} from 'react-admin'; +import { useRootSelector } from '@dslab/ra-root-selector'; +import { useWatch } from 'react-hook-form'; +import ContentSave from '@mui/icons-material/Save'; + +export const ReferencedArrayInput = (props: { + reference: string; + source: string; + record?: any; + resource?: string; + label?: string; + helperText?: string; +}) => { + const { reference, source, label, helperText } = props; + const record = useRecordContext(props); + const resource = useResourceContext(props); + const { root: realmId } = useRootSelector(); + const dataProvider = useDataProvider(); + const notify = useNotify(); + const refresh = useRefresh(); + + //fetch related to resolve relations + const { data } = useGetList(reference, { + pagination: { page: 1, perPage: 100 }, + sort: { field: 'name', order: 'ASC' }, + }); + + if (!record) return null; + + //inflate back flattened fields + const field = useWatch({ name: source, defaultValue: [] }); + const handleSave = e => { + e.stopPropagation(); + if ( + dataProvider && + record && + data !== undefined && + field !== undefined + ) { + const value = data.filter(g => field.includes(g.id)); + + dataProvider + .invoke({ + path: + resource + + '/' + + realmId + + '/' + + record.id + + '/' + + reference, + body: JSON.stringify(value), + options: { + method: 'PUT', + }, + }) + .then(() => { + notify('ra.notification.updated', { + messageArgs: { smart_count: 1 }, + }); + refresh(); + }); + } + }; + + return ( + <> + + + + + + + )} + + + + ); +}; + +export const DashboardHorizontalCard = (props: { + title: string | false; + icon: ReactElement; + text?: string; + secondaryText?: string | ReactElement; + number?: number; + to?: string | false; + elevation?: number; +}) => { + const { title, icon, number, text, secondaryText, to, elevation } = props; + const translate = useTranslate(); + const theme = useTheme(); + + const bgColor = alpha(theme.palette?.primary?.main, 0.08); + + return ( + 0 + ? '2px solid ' + theme.palette.primary.main + : '0 none', + }} + > + + + + {icon} + + + {title && ( + + )} + {number !== undefined && ( + + + {number} + + + {text} + + + )} + + + {to && ( + + )} + + + {secondaryText && + (isValidElement(secondaryText) ? ( + secondaryText + ) : ( + + {secondaryText} + + ))} + + + ); +}; + +export const DashboardTextCard = (props: { + title: string | false; + icon: ReactElement; + resource?: string; + text?: string; + number?: number; + secondaryText?: string | ReactElement; + to?: string | false; + elevation?: number; +}) => { + const { title, icon, number, text, secondaryText, to, elevation } = props; + const translate = useTranslate(); + const theme = useTheme(); + const bgColor = alpha(theme.palette?.primary?.main, 0.08); + + return ( + 0 + ? '2px solid ' + theme.palette.primary.main + : '0 none', + }} + > + {title && ( + + )} + + {number !== undefined && ( + + + {number} + + {text && ( + + {translate(text)} + + )} + + )} + {secondaryText && + (isValidElement(secondaryText) ? ( + secondaryText + ) : ( + + {secondaryText} + + ))} + {to && ( + <> + + + + + )} + + + ); +}; diff --git a/dev-console/src/dataProvider.ts b/dev-console/src/dataProvider.ts new file mode 100644 index 000000000..c699fb0c1 --- /dev/null +++ b/dev-console/src/dataProvider.ts @@ -0,0 +1,328 @@ +import { stringify } from 'query-string'; +import { fetchUtils, DataProvider } from 'ra-core'; +import jsonServerProvider from 'ra-data-json-server'; +import { Options } from 'react-admin'; + +const fetchJson = (url: string, options: Options = {}) => { + if (!options.headers) { + options.headers = new Headers({ Accept: 'application/json' }); + } + + options.credentials = 'include'; + + return fetchUtils.fetchJson(url, options); +}; + +export default (baseUrl: string, httpClient = fetchJson): DataProvider => { + const apiUrl = baseUrl + '/console/dev'; + const provider = jsonServerProvider(apiUrl, httpClient); + + return { + apiUrl: async () => apiUrl, + invoke: ({ + path, + params, + body, + options, + }: { + path: string; + params?: any; + body?: string; + options?: Options; + }) => { + let url = `${apiUrl}/${path}`; + if (params) { + url = `${apiUrl}/${path}?${stringify(params)}`; + } + const opts = options ? options : {}; + if (body) { + opts.body = body; + } + return httpClient(url, opts).then(({ headers, json }) => { + return json; + }); + }, + myAuthorities: () => { + const url = `${apiUrl}/authorities`; + return httpClient(url).then(({ json }) => { + return json; + }); + }, + getList: (resource, params) => { + const { page, perPage } = params.pagination; + const { field, order } = params.sort; + const query = { + ...fetchUtils.flattenObject(params.filter), + sort: field + ',' + order, + page: page - 1, + size: perPage, + }; + let suffix = ''; + if ( + resource !== 'myrealms' && + resource.indexOf('/') === -1 && + params.meta?.root + ) { + suffix = '/' + params.meta.root; + } + const url = + `${apiUrl}/${resource}${suffix}` + `?${stringify(query)}`; + return httpClient(url).then(({ headers, json }) => { + if (json && Array.isArray(json)) { + return { data: json, total: json.length }; + } + if (!json.content) { + throw new Error('the response must match page<> model'); + } + return { + data: json.content, + total: parseInt(json.totalElements, 10), + }; + }); + }, + getOne: (resource, params) => { + let suffix = ''; + if ( + resource !== 'myrealms' && + resource.indexOf('/') === -1 && + params.meta?.root + ) { + suffix = '/' + params.meta.root; + } + + const flatten = params.meta?.flatten || []; + + const url = `${apiUrl}/${resource}${suffix}` + `/${params.id}`; + return httpClient(url).then(({ status, json }) => { + if (status !== 200) { + throw new Error('Invalid response status ' + status); + } + + //flatten nested fields if required + if (json) { + for (const k of flatten) { + if (k in json) { + if (Array.isArray(json[k])) { + json[k] = json[k].map(e => { + return typeof e === 'object' && 'id' in e + ? e['id'] + : e; + }); + } else if ( + typeof json[k] === 'object' && + 'id' in json[k] + ) { + json[k] = json[k]['id']; + } + } + } + } + + return { + data: json, + }; + }); + }, + getMany: (resource, params) => { + //no pagination! + let prefix = ''; + if ( + resource !== 'myrealms' && + resource.indexOf('/') === -1 && + params.meta?.root + ) { + prefix = '/' + params.meta.root; + } + const url = `${apiUrl}/${resource}${prefix}`; + + return Promise.all( + params.ids.map(id => { + //remap id from nested objects if necessary + if (typeof id === 'object' && 'id' in id) { + return httpClient(`${url}/${id['id']}`); + } + + return httpClient(`${url}/${id}`); + }) + ).then(responses => ({ + data: responses.map(({ json }) => json), + })); + }, + + //TODO anche qui da fixare con param + getManyReference: (resource, params) => { + const { page, perPage } = params.pagination; + const { field, order } = params.sort; + const query = { + ...fetchUtils.flattenObject(params.filter), + [params.target]: params.id, + sort: field + ',' + order, + page: page - 1, + size: perPage, + }; + let prefix = ''; + if ( + resource !== 'myrealms' && + resource.indexOf('/') === -1 && + params.meta?.root + ) { + prefix = '/' + params.meta.root; + } + const url = + `${apiUrl}/${resource}${prefix}` + `?${stringify(query)}`; + return httpClient(url).then(({ headers, json }) => { + if (json && Array.isArray(json)) { + return { data: json, total: json.length }; + } + if (!json.content) { + throw new Error('the response must match page<> model'); + } + return { + data: json.content, + total: parseInt(json.totalElements, 10), + }; + }); + }, + update: (resource, params) => { + let suffix = ''; + if ( + resource !== 'myrealms' && + resource.indexOf('/') === -1 && + params.meta?.root + ) { + suffix = '/' + params.meta.root; + } + + const flatten = params.meta?.flatten || []; + + const url = `${apiUrl}/${resource}${suffix}` + `/${params.id}`; + return httpClient(url, { + method: 'PUT', + body: + typeof params.data === 'string' + ? params.data + : JSON.stringify(params.data), + }).then(({ status, json }) => { + if (status !== 200) { + throw new Error('Invalid response status ' + status); + } + + //flatten nested fields if required + if (json) { + for (const k of flatten) { + if (k in json) { + if (Array.isArray(json[k])) { + json[k] = json[k].map(e => { + return typeof e === 'object' && 'id' in e + ? e['id'] + : e; + }); + } else if ( + typeof json[k] === 'object' && + 'id' in json[k] + ) { + json[k] = json[k]['id']; + } + } + } + } + + return { + data: json, + }; + }); + }, + updateMany: (resource, params) => { + let prefix = ''; + if ( + resource !== 'myrealms' && + resource.indexOf('/') === -1 && + params.meta?.root + ) { + prefix = '/' + params.meta.root; + } + const url = `${apiUrl}${prefix}/${resource}`; + + //make a distinct call for every entry + return Promise.all( + params.ids.map(id => + httpClient(`${url}/${id}`, { + method: 'PUT', + body: JSON.stringify(params.data), + }) + ) + ).then(responses => ({ + data: responses.map(({ json }) => json.id), + })); + }, + create: (resource, params) => { + let method = `POST`; + let headers = { + 'Access-Control-Allow-Origin': '*', + }; + let body: any; + + let suffix = ''; + if ( + resource !== 'myrealms' && + resource.indexOf('/') === -1 && + params.meta?.root + ) { + suffix = '/' + params.meta.root; + } + let url = `${apiUrl}/${resource}${suffix}`; + + if (params.meta.import) { + method = `PUT`; + let formData = new FormData(); + formData.append('yaml', String(params.data)); + body = formData; + url = url + '?reset=' + params.meta.resetId; + } else { + body = JSON.stringify(params?.data); + } + return httpClient(url, { + method: method, + headers: new Headers(headers), + body: body, + }).then(({ json }) => ({ + data: { ...params.data, id: json?.id } as any, + })); + }, + delete: (resource, params) => { + let suffix = ''; + if ( + resource !== 'myrealms' && + resource.indexOf('/') === -1 && + params.meta?.root + ) { + suffix = '/' + params.meta.root; + } + const url = `${apiUrl}/${resource}${suffix}` + `/${params.id}`; + + return httpClient(url, { + method: 'DELETE', + }).then(({ json }) => ({ data: json })); + }, + deleteMany: (resource, params) => { + let prefix = ''; + if ( + resource !== 'myrealms' && + resource.indexOf('/') === -1 && + params.meta?.root + ) { + prefix = '/' + params.meta.root; + } + const url = `${apiUrl}${prefix}/${resource}`; + + //make a distinct call for every entry + return Promise.all( + params.ids.map(id => + httpClient(`${url}/${id}`, { + method: 'DELETE', + }) + ) + ).then(responses => ({ data: responses.map(({ json }) => json) })); + }, + }; +}; diff --git a/dev-console/src/developers/DeveloperCreate.tsx b/dev-console/src/developers/DeveloperCreate.tsx new file mode 100644 index 000000000..f100a1f40 --- /dev/null +++ b/dev-console/src/developers/DeveloperCreate.tsx @@ -0,0 +1,143 @@ +import { + Form, + SaveButton, + TextInput, + useInput, + useRecordContext, + useTranslate, +} from 'react-admin'; +import { + Box, + DialogActions, + Divider, + FormControl, + FormGroup, + FormLabel, + Grid, + Stack, + Switch, + Typography, +} from '@mui/material'; +import { Page } from '../components/Page'; +import { authorities } from '../idps/utils'; +import { useState } from 'react'; + +export const DeveloperCreateForm = () => { + return ( +
+ + + + + + + + + + +
+ ); +}; + +export const DeveloperEditForm = () => { + const record = useRecordContext(); + + if (!record) return null; + + return ( +
+ + + + + + +
+ ); +}; + +export const AuthoritiesInput = () => { + const translate = useTranslate(); + const record = useRecordContext(); + const { field } = useInput({ + source: 'authorities', + }); + + const value: any[] = field?.value || []; + + const handleSwitch = role => { + return (event: React.ChangeEvent) => { + const keep = value.filter(e => e.role !== role); + const edit = event.target.checked + ? [{ realm: record.realm, role: role }] + : []; + const res = [...keep, ...edit]; + + field.onChange(res); + }; + }; + + //hard-coded + const roles = ['ROLE_DEVELOPER', 'ROLE_ADMIN']; + + return ( + + + {translate('dialog.authorities.helperText')} + + + {roles.map(r => { + const checked = value.find(a => a.role === r) || false; + + return ( + + + + + + {translate( + 'authorities.' + r + '.name' + )} + + + {r} + + + {translate( + 'authorities.' + + r + + '.description' + )} + + + + + + + + + + ); + })} + + + ); +}; diff --git a/dev-console/src/developers/DeveloperIcon.tsx b/dev-console/src/developers/DeveloperIcon.tsx new file mode 100644 index 000000000..bc84bbd2e --- /dev/null +++ b/dev-console/src/developers/DeveloperIcon.tsx @@ -0,0 +1,5 @@ +import DeveloperMode from '@mui/icons-material/DeveloperMode'; +import AdminPanelSettings from '@mui/icons-material/AdminPanelSettings'; + +export const DeveloperIcon = DeveloperMode; +export const AdminIcon = AdminPanelSettings; diff --git a/dev-console/src/developers/DeveloperList.tsx b/dev-console/src/developers/DeveloperList.tsx new file mode 100644 index 000000000..2a4998c97 --- /dev/null +++ b/dev-console/src/developers/DeveloperList.tsx @@ -0,0 +1,133 @@ +import { + List, + SearchInput, + Datagrid, + TopToolbar, + useTranslate, + useRecordContext, + useResourceContext, + DeleteButton, +} from 'react-admin'; +import { Box } from '@mui/material'; +import { YamlExporter } from '../components/YamlExporter'; + +import { isValidElement, ReactElement } from 'react'; +import { useRootSelector } from '@dslab/ra-root-selector'; +import { DeveloperCreateForm, DeveloperEditForm } from './DeveloperCreate'; +import { + CreateInDialogButton, + EditInDialogButton, +} from '@dslab/ra-dialog-crud'; +import { PageTitle } from '../components/PageTitle'; +import { IdField } from '../components/IdField'; +import { NameField } from '../components/NameField'; +import { Page } from '../components/Page'; +import { TagsField } from '../components/TagsField'; +import { DropDownButton } from '../components/DropdownButton'; +import { RowButtonGroup } from '../components/RowButtonGroup'; +import { AuthoritiesIcon } from '../components/AuthoritiesDialog'; + +export const DeveloperList = () => { + const translate = useTranslate(); + return ( + + + } + filters={DeveloperFilters} + sort={{ field: 'name', order: 'ASC' }} + component={Box} + empty={false} + > + + + + ); +}; + +export const DeveloperListView = (props: { + actions?: ReactElement | boolean; +}) => { + const { actions: actionProps = true } = props; + + const actions = !actionProps ? ( + false + ) : isValidElement(actionProps) ? ( + actionProps + ) : ( + + ); + + return ( + + } + source="name" + label="field.name.name" + sortable={false} + /> + + + {actions !== false && actions} + + ); +}; + +export const DeveloperActionsButtons = () => { + const record = useRecordContext(); + + if (!record) { + return null; + } + + return ( + + + } + > + + + + + + ); +}; + +export const DeveloperFilters = []; + +export const DeveloperListActions = () => { + const { root: realmId } = useRootSelector(); + const transform = (data: any) => { + return { + ...data, + realm: realmId, + }; + }; + + return ( + + + + + + ); +}; diff --git a/dev-console/src/developers/index.ts b/dev-console/src/developers/index.ts new file mode 100644 index 000000000..aa1a6d805 --- /dev/null +++ b/dev-console/src/developers/index.ts @@ -0,0 +1,8 @@ +import { DeveloperIcon } from './DeveloperIcon'; +import { DeveloperList } from './DeveloperList'; + +export default { + icon: DeveloperIcon, + list: DeveloperList, + recordRepresentation: record => record.subjectId, +}; diff --git a/dev-console/src/group/GroupCreate.tsx b/dev-console/src/group/GroupCreate.tsx new file mode 100644 index 000000000..02dffd2c0 --- /dev/null +++ b/dev-console/src/group/GroupCreate.tsx @@ -0,0 +1,32 @@ +import { Form, SaveButton, TextInput } from 'react-admin'; +import { DialogActions, Stack } from '@mui/material'; +import { Page } from '../components/Page'; + +export const GroupCreateForm = () => { + return ( +
+ + + + + + + + + + +
+ ); +}; diff --git a/dev-console/src/group/GroupEdit.tsx b/dev-console/src/group/GroupEdit.tsx new file mode 100644 index 000000000..63ade3521 --- /dev/null +++ b/dev-console/src/group/GroupEdit.tsx @@ -0,0 +1,161 @@ +import { Box } from '@mui/material'; +import { + AutocompleteArrayInput, + Edit, + Labeled, + NumberField, + ReferenceArrayInput, + SaveButton, + TabbedForm, + TextField, + TextInput, + Toolbar, + TopToolbar, + useGetList, + useRecordContext, + useTranslate, +} from 'react-admin'; +import { InspectButton } from '@dslab/ra-inspect-button'; +import { DeleteWithDialogButton } from '@dslab/ra-delete-dialog-button'; +import { IdField } from '../components/IdField'; +import { Page } from '../components/Page'; +import { DatagridArrayInput } from '@dslab/ra-datagrid-input'; +import { SectionTitle } from '../components/SectionTitle'; +import { RefreshingExportButton } from '../components/RefreshingExportButton'; +import { ResourceTitle } from '../components/ResourceTitle'; + +export const GroupEdit = () => { + //fetch related to resolve relations + const { data: roles } = useGetList('roles', { + pagination: { page: 1, perPage: 100 }, + sort: { field: 'name', order: 'ASC' }, + }); + + //inflate back flattened fields + const transform = data => ({ + ...data, + roles: roles?.filter(r => data.roles.includes(r.id)), + }); + + return ( + + } + mutationMode="optimistic" + component={Box} + redirect={'edit'} + transform={transform} + queryOptions={{ meta: { flatten: ['roles'] } }} + mutationOptions={{ meta: { flatten: ['roles'] } }} + > + + + + + ); +}; + +const GroupEditForm = () => { + const translate = useTranslate(); + const record = useRecordContext(); + if (!record) return null; + + return ( + } syncWithLocation={false}> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]} + dialogFilterDefaultValues={{ q: '' }} + label="field.members.name" + helperText="field.members.helperText" + > + + + + + + + + ); +}; + +const ActionsToolbar = () => { + const record = useRecordContext(); + if (!record) return null; + + return ( + + + + + + ); +}; +const TabToolbar = () => ( + + + +); diff --git a/dev-console/src/group/GroupIcon.tsx b/dev-console/src/group/GroupIcon.tsx new file mode 100644 index 000000000..549ff7c97 --- /dev/null +++ b/dev-console/src/group/GroupIcon.tsx @@ -0,0 +1,2 @@ +import GroupMuiIcon from '@mui/icons-material/Group'; +export const GroupIcon = GroupMuiIcon; diff --git a/dev-console/src/group/GroupList.tsx b/dev-console/src/group/GroupList.tsx new file mode 100644 index 000000000..2239ee24e --- /dev/null +++ b/dev-console/src/group/GroupList.tsx @@ -0,0 +1,101 @@ +import { + List, + SearchInput, + Datagrid, + TopToolbar, + useTranslate, + NumberField, + ExportButton, +} from 'react-admin'; +import { Box } from '@mui/material'; +import { YamlExporter } from '../components/YamlExporter'; + +import React, { isValidElement, ReactElement } from 'react'; +import { useRootSelector } from '@dslab/ra-root-selector'; +import { GroupCreateForm } from './GroupCreate'; +import { CreateInDialogButton } from '@dslab/ra-dialog-crud'; +import { PageTitle } from '../components/PageTitle'; +import { ActionsButtons } from '../components/ActionsButtons'; +import { IdField } from '../components/IdField'; +import { GroupIcon } from './GroupIcon'; +import { NameField } from '../components/NameField'; +import { Page } from '../components/Page'; + +export const GroupList = () => { + const translate = useTranslate(); + return ( + + + } + filters={GroupFilters} + sort={{ field: 'name', order: 'ASC' }} + component={Box} + empty={false} + > + + + + ); +}; + +export const GroupListView = (props: { actions?: ReactElement | boolean }) => { + const { actions: actionProps = true } = props; + + const actions = !actionProps ? ( + false + ) : isValidElement(actionProps) ? ( + actionProps + ) : ( + + ); + + return ( + + } + /> + + + {actions !== false && actions} + + ); +}; + +const GroupFilters = []; + +const GroupListActions = () => { + const { root: realmId } = useRootSelector(); + const transform = (data: any) => { + return { + ...data, + realm: realmId, + }; + }; + + return ( + + + + + + + ); +}; diff --git a/dev-console/src/group/index.tsx b/dev-console/src/group/index.tsx new file mode 100644 index 000000000..4e76bd10d --- /dev/null +++ b/dev-console/src/group/index.tsx @@ -0,0 +1,11 @@ +import { GroupEdit } from './GroupEdit'; +import { GroupIcon } from './GroupIcon'; +import { GroupList } from './GroupList'; + +export default { + name: 'groups', + list: GroupList, + edit: GroupEdit, + icon: GroupIcon, + recordRepresentation: record => record.group, +}; diff --git a/dev-console/src/i18n/de/index.ts b/dev-console/src/i18n/de/index.ts new file mode 100644 index 000000000..82d26e09a --- /dev/null +++ b/dev-console/src/i18n/de/index.ts @@ -0,0 +1,9 @@ +import { TranslationMessages } from 'ra-core'; +import raMessages from 'ra-language-english'; +import utils from '../../utils'; + +const germanMessages: TranslationMessages = { + ra: utils.deepCopy(raMessages.ra), +}; + +export default germanMessages; diff --git a/dev-console/src/i18n/en/actions.json b/dev-console/src/i18n/en/actions.json new file mode 100644 index 000000000..6b30db423 --- /dev/null +++ b/dev-console/src/i18n/en/actions.json @@ -0,0 +1,16 @@ +{ + "actions": "Actions", + "authorities": "Authorities", + "click_to_copy": "Click to copy", + "enable_disable": "Enable/Disable", + "manage": "Manage", + "register": "Register", + "select": "Select", + "show": "Show", + "test": "Test", + "disable": "Block", + "lock": "Lock", + "verify": "Verify", + "reset": "Unconfirm", + "confirm": "Confirm" +} diff --git a/dev-console/src/i18n/en/errors.json b/dev-console/src/i18n/en/errors.json new file mode 100644 index 000000000..78e803c95 --- /dev/null +++ b/dev-console/src/i18n/en/errors.json @@ -0,0 +1,29 @@ +{ + "already_registered": "Already registered", + "authentication_service": "Authentication problem. Please try again later", + "bad_credentials": "Invalid user or password", + "internal_error": "Internal error. Please try again", + "invalid_data": "Invalid data", + "invalid": { + "contains_whitespace": "Invalid password: contains whitespaces", + "empty": "Invalid password: empty password", + "max_length": "Invalid password: too long", + "min_length": "Invalid password: too short", + "password_reuse": "Invalid password: password reuse", + "require_alpha": "Invalid password: alpha char required", + "require_number": "Invalid password: number required", + "require_uppercase_alpha": "Invalid password: uppercase alpha char required", + "require_special": "Invalid password: special character required", + "not_match": "Invalid password: the passwords do not match", + "policy": "Invalid password: the password does not satisfy the policy" + }, + "missing_data": "Missing data", + "not_editable": "Not editable", + "invalid_field": "Invalid field", + "unsupported_operation": "Unsupported operation", + "registration": { + "invalid": "Invalid registration", + "error": "Registration error" + }, + "provider_is_enabled": "Provider is not editable when enabled" +} \ No newline at end of file diff --git a/dev-console/src/i18n/en/fields.json b/dev-console/src/i18n/en/fields.json new file mode 100644 index 000000000..3964e1276 --- /dev/null +++ b/dev-console/src/i18n/en/fields.json @@ -0,0 +1,597 @@ +{ + "id": { + "name": "Id", + "helperText": "Unique identifier" + }, + "name": { + "name": "Name", + "helperText": "Human readable name" + }, + "description": { + "name": "Description", + "helperText": "Text describing the element, used for views" + }, + "type": { + "name": "Type", + "helperText": "Type field" + }, + "clientId": { + "name": "ClientId", + "helperText": "Client (unique) identifier" + }, + "clientSecret": { + "name": "Client Secret", + "helperText": "Client Secret (unique) identifier" + }, + "clientJwk": { + "name": "Client Private Key (JWK)", + "helperText": "" + }, + "clientName": { + "name": "Client Name", + "helperText": "" + }, + "clientAuthenticationMethod": { + "name": "Client Authentication Method", + "helperText": "" + }, + "enablePkce": { + "name": "Enable PKCE", + "helperText": "" + }, + "userNameAttributeName": { + "name": "Username Attribute", + "helperText": "" + }, + "subjectType": { + "name": "Subject attribute (if different from sub)", + "helperText": "" + }, + "subAttributeName": { + "name": "Subject attribute (if different from sub)", + "helperText": "" + }, + "trustEmailAddress": { + "name": "trustEmailAddress", + "helperText": "" + }, + "requireEmailAddress": { + "name": "requireEmailAddress", + "helperText": "" + }, + "alwaysTrustEmailAddress": { + "name": "alwaysTrustEmailAddress", + "helperText": "" + }, + "authorizationUri": { + "name": "Authorization Endpoint", + "helperText": "" + }, + "tokenUri": { + "name": "Token Endpoint", + "helperText": "" + }, + "jwkSetUri": { + "name": "JWKS Endpoint", + "helperText": "" + }, + "userInfoUri": { + "name": "Userinfo Endpoint", + "helperText": "" + }, + "issuerUri": { + "name": "Issuer Endpoint", + "helperText": "" + }, + "propagateEndSession": { + "name": "Propagate end session to idp", + "helperText": "" + }, + "respectTokenExpiration": { + "name": "Use expiration from token for session", + "helperText": "" + }, + "promptMode": { + "name": "Prompt Mode", + "helperText": "" + }, + "template_override": { + "name": "Template Override", + "helperText": "" + }, + "authorization_endpoint": "Authorization Endpoint", + "token_endpoint": "Token Endpoint", + "jwks_uri": "JWKS endpoint", + "userinfo_endpoint": "Userinfo endpoint", + "introspection_endpoint": "Introspection endpoint", + "revocation_endpoint": "Revocation endpoint", + "registration_endpoint": "Registration endpoint", + "end_session_endpoint": "Endsession endpoint", + "slug": { + "name": "Slug", + "helperText": "Path-style (unique) identifier" + }, + "public": { + "name": "Public", + "helperText": "Toggle for public/private visibility" + }, + "languages": { + "name": "Languages", + "helperText": "List of languages (codes) enabled" + }, + "applicationType": { + "name": "Application type", + "helperText": "Type of (OAuth2) application" + }, + "title": { + "name": "Title", + "helperText": "Title used for views" + }, + "customStyle": { + "name": "Custom style", + "helperText": "Define a custom style sheet (CSS) to be injected in pages" + }, + "namespace": { + "name": "Namespace", + "helperText": "Service Namespace" + }, + "scope": { + "name": "Scope", + "helperText": "" + }, + "authority": { + "name": "Authority", + "helperText": "" + }, + "approvalRoles": { + "name": "Authorization with realm roles", + "helperText": "approvalRoles.helperText" + }, + "approvalFunction": { + "name": "Authorization with approval function", + "helperText": "" + }, + "approvalAny": { + "name": "One of", + "helperText": "" + }, + "approvalRequired": { + "name": "Authorization with explicit approval", + "helperText": "" + }, + "multiple": { + "name": "Is Array", + "helperText": "" + }, + "claimMapping": { + "user": { + "name": "User claim mapping", + "helperText": "Claim mapping function should return fully-qualified claims of the current service ONLY. Service namespace is enforced when claims are added to tokens" + }, + "client": { + "name": "Client claim mapping", + "helperText": "Claim mapping function should return fully-qualified claims of the current service ONLY. Service namespace is enforced when claims are added to tokens" + } + }, + "key": { + "name": "Key", + "helperText": "" + }, + "groups": { + "name": "Groups", + "helperText": "" + }, + "roles": { + "name": "Roles", + "helperText": "" + }, + "jwks": { + "name": "Client Key Set (JWKS)" + }, + "context": "context", + "result": "result", + "providers": { + "name": "Providers", + "helperText": "" + }, + "scopes": { + "name": "Scopes", + "helperText": "" + }, + "attributeSets": { + "name": "Attribute Sets", + "helperText": "" + }, + "enabled": { + "name": "Active" + }, + "registered": { + "name": "Registered" + }, + "username": { + "name": "Username" + }, + "subjectId": { + "name": "SubjectId", + "helperText": "" + }, + "identifier": { + "name": "Set Identifier", + "helperText": "" + }, + "accounts": { + "name": "accounts.name" + }, + "status": { + "name": "status.name" + }, + "role": { + "name": "Role", + "helperText": "" + }, + "subjects": { + "name": "Subjects", + "helperText": "Numer of associated subjects" + }, + "permissions": { + "name": "Permission", + "helperText": "" + }, + "group": { + "name": "Group", + "helperText": "" + }, + "members": { + "name": "Members", + "helperText": "Total number of members" + }, + "email": { + "name": "Email Address", + "helperText": "" + }, + "keys": { + "name": "keys.name" + }, + "": "", + "events": { + "helperText": "", + "name": "Audit events" + }, + "linkable": { + "helperText": "", + "name": "Enable account linking" + }, + "notes": { + "helperText": "", + "name": "Notes" + }, + "oauth2": { + "accessTokenValidity": { + "helperText": "", + "name": "Access token validity (sec)" + }, + "applicationType": { + "helperText": "", + "name": "Application type" + }, + "authenticationMethods": { + "helperText": "", + "name": "Authentication methods" + }, + "authorizedGrantTypes": { + "helperText": "", + "name": "Grant types" + }, + "enableClientRegistration": { + "helperText": "Dynamic client registration with management (OAuth2 and OIDC). Authorized parties (with a valid bearer token) will be able to register a client", + "name": "Enable Dynamic Client Registration" + }, + "firstParty": { + "helperText": "", + "name": "First party" + }, + "idTokenClaims": { + "helperText": "", + "name": "IdToken custom claims" + }, + "openClientRegistration": { + "helperText": "Open Dynamic Registration disables authentication for DCR endpoints", + "name": "Enable Open Dynamic Client Registration" + }, + "redirectUris": { + "helperText": "", + "name": "Redirect uris" + }, + "refreshTokenRotation": { + "helperText": "", + "name": "Refresh token rotation" + }, + "refreshTokenValidity": { + "helperText": "", + "name": "Refresh token validity (sec)" + }, + "subjectType": { + "helperText": "", + "name": "Subject type" + }, + "tokenType": { + "helperText": "", + "name": "Token type" + } + }, + "persistence": { + "helperText": "", + "name": "Persistence" + }, + "position": { + "helperText": "", + "name": "Localization" + }, + "tos": { + "approveTOS": { + "helperText": "", + "name": "Approve Terms of Service" + }, + "enableTOS": { + "helperText": "", + "name": "Enable Terms of Service" + } + }, + "webhooks": { + "afterTokenGrant": { + "helperText": "", + "name": "After token grant webhook" + }, + "afterUserApproval": { + "helperText": "", + "name": "After user approval webhook" + }, + "beforeTokenGrant": { + "helperText": "webhooks.beforeTokenGrant.helperText", + "name": "Before token grant webhook" + }, + "beforeUserApproval": { + "helperText": "", + "name": "Before user approval webhook" + } + }, + "time": { + "name": "Time" + }, + "principal": { + "name": "Principal" + }, + "issuer": "Issuer", + "tosAccepted": { + "name": "Approved" + }, + "account": { + "active": "Active", + "inactive": "Inactive", + "verified": "Verified", + "unverified": "Unverified", + "unlocked": "Unlocked", + "confirmed": "Confirmed", + "unconfirmed": "Unconfirmed" + }, + "enableRegistration": { + "name": "Enable Registration", + "helperText": "" + }, + "enableDelete": { + "name": "Enable Delete", + "helperText": "" + }, + "enableUpdate": { + "name": "Enable Update", + "helperText": "" + }, + "confirmationRequired": { + "name": "Confirmation Required", + "helperText": "" + }, + "confirmationValidity": { + "name": "Confirmation duration (seconds)", + "helperText": "" + }, + "resource": { + "name": "Resource", + "helperText": "" + }, + "usermode": { + "name": "UserMode", + "helperText": "" + }, + "maxSessionDuration": { + "name": "Max session duration", + "helperText": "Session Management" + }, + "displayAsButton": { + "name": "Show as button", + "helperText": "Display Management" + }, + "allowUntrustedAttestation": { + "name": "Allow untrusted Attestation", + "helperText": "Credentials Management" + }, + "requireResidentKey": { + "name": "Resident key", + "helperText": "User verification" + }, + "registrationTimeout": { + "name": "Registration timeout (seconds)", + "helperText": "Operation Management" + }, + "loginTimeout": { + "name": "Login timeout (seconds)", + "helperText": "Operation Management" + }, + "requireAccountConfirmation": { + "name": "Require account confirmation", + "helperText": "User Management" + }, + "enablePasswordReset": { + "name": "Reset Enabled", + "helperText": "Password Management" + }, + "passwordResetValidity": { + "name": "Reset duration (seconds)", + "helperText": "Password Management" + }, + "passwordMinLength": { + "name": "Min length", + "helperText": "Password Policies" + }, + "passwordMaxLength": { + "name": "Max length", + "helperText": "Password Policies" + }, + "passwordRequireAlpha": { + "name": "Require letters", + "helperText": "Password Policies" + }, + "passwordRequireSpecial": { + "name": "Require special characters", + "helperText": "Password Policies" + }, + "passwordRequireUppercaseAlpha": { + "name": "Require uppercase letters", + "helperText": "Password Policies" + }, + "passwordRequireNumber": { + "name": "Require numbers", + "helperText": "Password Policies" + }, + "passwordSupportWhitespace": { + "name": "Support whitespace", + "helperText": "Password Policies" + }, + "passwordMaxDays": { + "name": "Max duration (days)", + "helperText": "Password Security" + }, + "passwordKeepNumber": { + "name": "Old passwords to keep (reuse protection)", + "helperText": "Password Security" + }, + "teamId": { + "name": "Team ID", + "helperText": "" + }, + "keyId": { + "name": "Key ID", + "helperText": "" + }, + "privateKey": { + "name": "Client Private Key (PEM)", + "helperText": "" + }, + "askNameScope": { + "name": "Full name", + "helperText": "User Attributes" + }, + "askEmailScope": { + "name": "Email", + "helperText": "User Attributes" + }, + "clientJwks": { + "name": "Client Private Key (JWK)", + "helperText": "" + }, + "federationJwks": { + "name": "Federation Key (JWK)", + "helperText": "" + }, + "claims": { + "name": "Claims", + "helperText": "" + }, + "organizationName": { + "name": "Organization Name", + "helperText": "" + }, + "contacts": { + "name": "Contacts", + "helperText": "" + }, + "trustAnchor": { + "name": "Trust Anchors", + "helperText": "" + }, + "trustMarks": { + "name": "Trust Marks", + "helperText": "" + }, + "authorityHints": { + "name": "Authority Hints", + "helperText": "" + }, + "acrValues": { + "name": "acrValues", + "helperText": "Advanced Configuration" + }, + "userInfoJWEAlg": { + "name": "userInfoJWEAlg", + "helperText": "Advanced Configuration" + }, + "userInfoJWEEnc": { + "name": "userInfoJWEEnc", + "helperText": "Advanced Configuration" + }, + "entityId": { + "name": "Entity ID", + "helperText": "" + }, + "signingKey": { + "name": "Signing Key", + "helperText": "Signing" + }, + "signingCertificate": { + "name": "Signing Certificate", + "helperText": "Signing" + }, + "organizationDisplayName": { + "name": "Organization Display Name", + "helperText": "Organization information" + }, + "organizationUrl": { + "name": "Organization Url", + "helperText": "Organization information" + }, + "contactPerson_EmailAddress": { + "name": "Contact person email", + "helperText": "Contact person information" + }, + "contactPerson_IPACode": { + "name": "Contact person IPAcode", + "helperText": "Contact person information" + }, + "contactPerson_Type": { + "name": "Contact person phone", + "helperText": "Contact person information" + }, + "contactPerson_Public": { + "name": "Contact person Public", + "helperText": "Contact person information" + }, + "idps": { + "name": "Identity Providers", + "helperText": "IdP Configuration" + }, + "idpMetadataUrl": { + "name": "IdP Metadata Discovery URL", + "helperText": "IdP Configuration" + }, + "spidAttributes": { + "name": "Identity Providers", + "helperText": "SPID IdP Configuration" + }, + "spidLevel": { + "name": "Spid level", + "helperText": "SPID Advanced Configuration" + }, + "usernameAttributeName": { + "name": "Spid username attribute", + "helperText": "SAML Advanced Configuration" + } +} \ No newline at end of file diff --git a/dev-console/src/i18n/en/index.ts b/dev-console/src/i18n/en/index.ts new file mode 100644 index 000000000..3b8ec0f6a --- /dev/null +++ b/dev-console/src/i18n/en/index.ts @@ -0,0 +1,26 @@ +import { TranslationMessages } from 'ra-core'; +import raMessages from 'ra-language-english'; +import utils from '../../utils'; +import resources from './resources'; +import * as fields from './fields.json'; +import * as messages from './messages.json'; +import * as errors from './errors.json'; +import * as pages from './pages.json'; +import * as tabs from './tabs.json'; +import * as actions from './actions.json'; + +import translations from './translations'; + +const englishMessages: TranslationMessages = { + ra: utils.deepCopy(raMessages.ra), + resources: resources, + field: fields, + message: messages, + error: errors, + page: pages, + tab: tabs, + action: actions, + ...translations, +}; + +export default englishMessages; diff --git a/dev-console/src/i18n/en/messages.json b/dev-console/src/i18n/en/messages.json new file mode 100644 index 000000000..2d0816ed9 --- /dev/null +++ b/dev-console/src/i18n/en/messages.json @@ -0,0 +1,5 @@ +{ + "content_copied_x": "%{x} copied", + "content_copied": "Content copied", + "registered": "Element registered" +} \ No newline at end of file diff --git a/dev-console/src/i18n/en/pages.json b/dev-console/src/i18n/en/pages.json new file mode 100644 index 000000000..5b2d7697f --- /dev/null +++ b/dev-console/src/i18n/en/pages.json @@ -0,0 +1,380 @@ +{ + "dashboard": { + "description": "Manage apps, users and services", + "logins_7_days": "Last 7 days logins", + "registrations_7_days": "Last 7 days registrations", + "tokens_7_days": "Last 7 days tokens" + }, + "myrealms": { + "name": "Realm |||| Realms" + }, + "apps": { + "list": { + "title": "Client applications", + "subtitle": "Manage web, mobile, server and IoT applications." + }, + "credentials": { + "header": { + "title": "Client credentials", + "subtitle": "Credentials used with OAuth2/OIDC for authenticating against AAC" + } + }, + "scopes": { + "header": { + "title": "API resources and scopes", + "subtitle": "Manage API access by enabling scopes for selected resources. Clients will be able to ask and obtain only scopes enabled in this section." + } + }, + "endpoints": { + "header": { + "title": "OAuth2 endpoints", + "subtitle": "AAC endpoints for OAuth2 and OpenId Connect." + } + }, + "audit": { + "title": "Audit log", + "subTitle": "Review audit log for the current application" + }, + "settings": { + "header": { + "title": "Basic settings", + "subtitle": "Configure application settings" + } + }, + "providers": { + "header": { + "title": "Providers", + "subtitle": "Identity providers are used to authenticate users via login. Only enabled (and active) providers will be available for this client." + } + }, + "configuration": { + "header": { + "title": "OAuth2 configuration", + "subtitle": "Client configuration for OAuth2/OIDC" + } + }, + "hooks": { + "claimMapping": { + "title": "Custom claim mapping", + "subtitle": "Custom mapping for claims generation, executed after token grants. The result will be used as provided to build client responses." + }, + "webhooks": { + "title": "WebHooks", + "subtitle": "Hooks are used to alter the token flow by performing actions and/or web calls" + } + }, + "roles": { + "header": { + "title": "Roles", + "subtitle": "Manage roles for the client application" + } + }, + "groups": { + "header": { + "title": "Groups", + "subtitle": "Manage groups for the client application" + } + } + }, + "groups": { + "list": { + "title": "Groups", + "subtitle": "Register and manage realm groups." + } + }, + "roles": { + "list": { + "title": "Roles", + "subtitle": "Register and manage realm roles." + }, + "permissions": { + "header": { + "subtitle": "Manage API permissions for the current role", + "title": "Permissions" + } + }, + "subjects": { + "header": { + "subtitle": "Manually manage subjects associated with this role", + "title": "Role subjects" + } + } + }, + "users": { + "list": { + "title": "Users", + "subtitle": "View and manage user, assign roles and groups" + } + }, + "idps": { + "list": { + "title": "Identity providers", + "subtitle": "Register and manage identity providers for authentication and identification." + }, + "settings": { + "basic": { + "title": "Basic settings", + "subtitle": "" + }, + "display": { + "title": "Display settings", + "subtitle": "" + }, + "advanced": { + "title": "Advanced settings", + "subtitle": "" + } + }, + "configuration": { + "title": "Configuration", + "subtitle": "" + }, + "hooks": { + "attribute": "Custom attribute mapping", + "attributeDesc": "Provide a function to transform principal attributes during login. Return a valid map with all the attributes", + "authFunction": "Authorization function", + "authFunctionDesc": "Provide a function to evaluate an authorization policy during the login flow. Return a boolean true/false to represent a decision" + }, + "apps": { + "title": "Client applications", + "description": "" + } + }, + "aps": { + "list": { + "title": "Attribute providers", + "subtitle": "Register and manage attribute providers." + }, + "settings": { + "basic": { + "title": "Basic settings", + "subtitle": "" + }, + "display": { + "title": "Display settings", + "subtitle": "" + }, + "advanced": { + "title": "Advanced settings", + "subtitle": "" + } + }, + "attributeSets": { + "header": { + "title": "Attribute Sets", + "subtitle": "" + } + }, + "configuration": { + "title": "Configuration", + "subtitle": "" + } + }, + "resources": { + "list": { + "title": "API resources", + "subtitle": "View and inspect resources and scopes." + } + }, + "audit": { + "list": { + "title": "Audit events", + "subtitle": "Review and inspect events for authentication, access and token usage." + } + }, + "services": { + "list": { + "title": "API services", + "subtitle": "Register and manage custom services for APIs." + } + }, + "attributeset": { + "list": { + "title": "Attribute sets", + "subtitle": "Register and manage custom attribute sets for users. Each custom attribute set will be available as custom profile for consumption both via profiles api and via token claims, with an associated scope `profile.setidentifier.me`" + }, + "attributes": { + "header": { + "subtitle": "", + "title": "Attributes" + } + }, + "settings": { + "header": { + "subtitle": "", + "title": "Basic settings" + } + } + }, + "scopes": { + "list": { + "title": "Scopes", + "subtitle": "View and inspect resources and scopes." + } + }, + "developers": { + "list": { + "subtitle": "", + "title": "Developers" + } + }, + "group": { + "members": { + "header": { + "title": "Members" + } + }, + "roles": { + "header": { + "subtitle": "Manage roles associated with the current group.", + "title": "Roles" + }, + "members": { + "subtitle": "members" + } + }, + "settings": { + "header": { + "subtitle": "", + "title": "Basic Settings" + } + }, + "subjects": { + "members": { + "subtitle": "Members" + } + } + }, + "login": { + "description": "", + "header": "Login" + }, + "realm": { + "developers": { + "header": { + "title": "Developers" + } + }, + "localization": { + "header": { + "subtitle": "Manage localization and internationalization settings", + "title": "Localization" + } + }, + "oauth2": { + "header": { + "subtitle": "Configure realm OAuth2/OIDC settings", + "title": "OAuth2 configuration" + } + }, + "roles": { + "developers": { + "subtitle": "developers" + } + }, + "settings": { + "header": { + "subtitle": "Manage basic settings for the realm", + "title": "Basic settings" + } + }, + "templates": { + "header": { + "subtitle": "Customize display settings and view templates", + "title": "Template and appearance" + } + }, + "tos": { + "header": { + "subtitle": "Configure ToS usage", + "title": "Terms of service" + } + } + }, + "realms": { + "list": { + "subtitle": "Create and manage realms", + "title": "Realms" + } + }, + "role": { + "settings": { + "header": { + "subtitle": "", + "title": "Basic settings" + } + } + }, + "service": { + "claim": { + "definition": { + "subtitle": "", + "title": "Claim definition" + } + }, + "claims": { + "header": { + "subtitle": "Claims are used to carry authorization info with access and/or id tokens", + "title": "Service claims" + }, + "mapping": { + "subtitle": "Claim mapping function should return fully-qualified claims of the current service ONLY. Service namespace is enforced when claims are added to tokens.", + "title": "User claim mapping" + } + }, + "scope": { + "authorizations": { + "subtitle": "", + "title": "Authorizations" + }, + "definition": { + "subtitle": "", + "title": "Scope definition" + } + }, + "scopes": { + "header": { + "subtitle": "Scopes are used to identify permissions on a resource managed by the service. Clients will ask for scopes during authorization.", + "title": "Service scopes" + } + }, + "settings": { + "header": { + "subtitle": "", + "title": "Basic settings" + } + } + }, + "user": { + "accounts": { + "subtitle": "Manage accounts for the current user", + "title": "Accounts" + }, + "apps": { + "subtitle": "Manage connected apps for the current user", + "title": "Connected Applications" + }, + "attributes": { + "attributes": { + "subtitle": "Review and manage additional attributes for the current user", + "title": "Additional Attributes" + }, + "identity": { + "subtitle": "Review attributes for the current user, as received from identity providers", + "title": "Identity Attributes" + } + }, + "groups": { + "subtitle": "Manage groups for the current user", + "title": "Groups" + }, + "roles": { + "subtitle": "Manage roles for the current user", + "title": "Roles" + }, + "tos": { + "subtitle": "Manage Terms of service for the current user", + "title": "Terms of service" + } + } +} diff --git a/dev-console/src/i18n/en/resources.ts b/dev-console/src/i18n/en/resources.ts new file mode 100644 index 000000000..623a40275 --- /dev/null +++ b/dev-console/src/i18n/en/resources.ts @@ -0,0 +1,40 @@ +export const resources = { + myrealms: { + name: 'Realm |||| Realms', + }, + apps: { + name: 'Client app |||| Client apps', + }, + groups: { + name: 'Group |||| Groups', + }, + roles: { + name: 'Role |||| Roles', + }, + users: { + name: 'User |||| Users', + }, + idps: { + name: 'Identity provider |||| Identity providers', + }, + aps: { + name: 'Attribute provider |||| Attribute providers', + }, + resources: { + name: 'API resource |||| API resources', + }, + audit: { + name: 'Audit |||| Audit', + }, + services: { + name: 'API service|||| API services', + }, + attributeset: { + name: 'Attribute set |||| Attribute sets', + }, + scopes: { + name: 'Scope |||| Scopes', + }, +}; + +export default resources; diff --git a/dev-console/src/i18n/en/tabs.json b/dev-console/src/i18n/en/tabs.json new file mode 100644 index 000000000..178ce3c26 --- /dev/null +++ b/dev-console/src/i18n/en/tabs.json @@ -0,0 +1,29 @@ +{ + "overview": "Overview", + "settings": "Settings", + "configuration": "Configuration", + "credentials": "Credentials", + "audit": "Audit", + "api_access": "Api access", + "roles": "Roles", + "groups": "Groups", + "users": "Users", + "members": "Members", + "subjects": "Subjects", + "providers": "Providers", + "attributeSets": "Attribute sets", + "scopes": "Scopes", + "claims": "Claims", + "accounts": "Accounts", + "apps": "Client apps", + "attributes": "Attributes", + "test": "Test", + "hooks": "Hooks", + "tos": "Terms of service", + "permissions": "Permissions", + "endpoints": "Endpoints", + "localization": "Localization", + "templates": "Templates", + "oauth2": "OAuth2", + "developers": "Developers" +} \ No newline at end of file diff --git a/dev-console/src/i18n/en/translations.ts b/dev-console/src/i18n/en/translations.ts new file mode 100644 index 000000000..911093964 --- /dev/null +++ b/dev-console/src/i18n/en/translations.ts @@ -0,0 +1,15 @@ +export const translations = { + admin: 'Admin', + developer: 'Developer', + user: 'User', + languages: { + english: 'English', + italian: 'Italian', + german: 'German', + }, + menu: { + configuration: 'Configuration', + }, +}; + +export default translations; diff --git a/dev-console/src/i18n/it/index.ts b/dev-console/src/i18n/it/index.ts new file mode 100644 index 000000000..b776701f8 --- /dev/null +++ b/dev-console/src/i18n/it/index.ts @@ -0,0 +1,9 @@ +import { TranslationMessages } from 'ra-core'; +import raMessages from '@dslab/ra-language-italian'; +import utils from '../../utils'; + +const italianMessages: TranslationMessages = { + ra: utils.deepCopy(raMessages.ra), +}; + +export default italianMessages; diff --git a/dev-console/src/i18nProvider.ts b/dev-console/src/i18nProvider.ts new file mode 100644 index 000000000..c5c36166b --- /dev/null +++ b/dev-console/src/i18nProvider.ts @@ -0,0 +1,24 @@ +import polyglotI18nProvider from 'ra-i18n-polyglot'; +import { TranslationMessages } from 'react-admin'; + +import italianMessages from './i18n/it'; +import germanMessages from './i18n/de'; +import englishMessages from './i18n/en'; + +const messages: Record = { + en: englishMessages, + it: italianMessages, + de: germanMessages, +}; + +export default polyglotI18nProvider( + (locale: string) => { + return messages[locale]; + }, + 'en', + [ + { locale: 'en', name: 'EN' }, + { locale: 'it', name: 'IT' }, + { locale: 'de', name: 'DE' }, + ] +); diff --git a/dev-console/src/idps/IdpCreate.tsx b/dev-console/src/idps/IdpCreate.tsx new file mode 100644 index 000000000..66b4e78c4 --- /dev/null +++ b/dev-console/src/idps/IdpCreate.tsx @@ -0,0 +1,55 @@ +import { + Form, + SaveButton, + SelectInput, + TextInput, + useDataProvider, +} from 'react-admin'; +import { DialogActions, Stack } from '@mui/material'; +import { Page } from '../components/Page'; +import { useEffect, useMemo, useState } from 'react'; +import { useRootSelector } from '@dslab/ra-root-selector'; + +export const IdpCreateForm = () => { + const dataProvider = useDataProvider(); + const { root: realmId } = useRootSelector(); + const [authorities, setAuthorities] = useState([]); + + useEffect(() => { + if (dataProvider) { + dataProvider + .invoke({ path: 'idps/' + realmId + '/authorities' }) + .then(data => { + setAuthorities(data || []); + }); + } + }, [dataProvider]); + + return ( +
+ + + ({ + id: a, + name: 'authority.' + a, + }))} + /> + + + + + + +
+ ); +}; diff --git a/dev-console/src/idps/IdpEdit.tsx b/dev-console/src/idps/IdpEdit.tsx new file mode 100644 index 000000000..34de48bbb --- /dev/null +++ b/dev-console/src/idps/IdpEdit.tsx @@ -0,0 +1,371 @@ +import { + Button, + Datagrid, + Edit, + IconButtonWithTooltip, + Labeled, + ReferenceManyField, + SaveButton, + TabbedForm, + TextField, + TextInput, + Toolbar, + TopToolbar, + TranslatableInputs, + useDataProvider, + useDelete, + useNotify, + useRecordContext, + useRefresh, + useTranslate, + useUpdate, +} from 'react-admin'; +import { InspectButton } from '@dslab/ra-inspect-button'; +import { DeleteWithDialogButton } from '@dslab/ra-delete-dialog-button'; +import { Page } from '../components/Page'; +import { JsonSchemaInput } from '@dslab/ra-jsonschema-input'; +import { Alert, Box, Typography } from '@mui/material'; +import { SectionTitle } from '../components/SectionTitle'; +import { AceEditorInput } from '@dslab/ra-ace-editor'; +import { RefreshingExportButton } from '../components/RefreshingExportButton'; +import { useRootSelector } from '@dslab/ra-root-selector'; +import { + getIdpSchema, + getIdpUiSchema, + schemaIdpSettings, + uiSchemaIdpSettings, +} from './schemas'; +import { ResourceTitle } from '../components/ResourceTitle'; +import PlayArrowIcon from '@mui/icons-material/PlayArrow'; +import StopIcon from '@mui/icons-material/Stop'; +import { getIdpIcon } from './utils'; +import { IdField } from '../components/IdField'; +import { useEffect, useMemo, useState } from 'react'; +import { DEFAULT_LANGUAGES } from '../App'; +import WarningIcon from '@mui/icons-material/WarningOutlined'; +import RegisteredIcon from '@mui/icons-material/VerifiedUser'; + +export const IdpEdit = () => { + return ( + + } + mutationMode="optimistic" + component={Box} + redirect={'edit'} + > + + + + + ); +}; +const IdpEditTitle = () => { + const record = useRecordContext(); + if (!record) return null; + + return ( + } + icon={getIdpIcon(record.authority, { + fontSize: 'large', + sx: { fontSize: '96px' }, + color: 'primary', + })} + /> + ); +}; + +const IdpTitle = () => { + const record = useRecordContext(); + if (!record) return null; + + return ( + + {record.name}{' '} + {record?.enabled && !record.registered && ( + + + + )} + {record.registered && ( + + + + )} + + ); +}; + +const IdpEditForm = () => { + const dataProvider = useDataProvider(); + const { root: realmId } = useRootSelector(); + const record = useRecordContext(); + const schema = useMemo(() => getIdpSchema(record.schema), [record]); + const [availableLocales, setAvailableLocales] = + useState(DEFAULT_LANGUAGES); + + useEffect(() => { + if (dataProvider && realmId) { + dataProvider.getOne('myrealms', { id: realmId }).then(data => { + if (data && 'localizationConfiguration' in data) { + setAvailableLocales( + (data.localizationConfiguration as any)['languages'] || + DEFAULT_LANGUAGES + ); + } + }); + } + }, [dataProvider, realmId]); + + if (!record) return null; + + return ( + } syncWithLocation={false}> + + + + + + + + + + + + + + + + + + + + + {availableLocales && ( + + + + + )} + + + + + + + + {schema && ( + + )} + + + + + + + + + + + + + + + + {/* {record.apps && record.apps.map(app => ( + + ))} */} + + + + + + + + + ); +}; + +const TabToolbar = () => { + const record = useRecordContext(); + const translate = useTranslate(); + + return ( + <> + {record.enabled && ( + } sx={{ mb: 2 }}> + {translate('error.provider_is_enabled')} + + )} + + + + + ); +}; + +const EditToolBarActions = () => { + const record = useRecordContext(); + if (!record) return null; + + return ( + + + + + + + ); +}; + +export const ToggleIdpButton = () => { + const record = useRecordContext(); + const { root: realmId } = useRootSelector(); + const notify = useNotify(); + const refresh = useRefresh(); + const [disable] = useDelete( + 'idps', + { + id: record.provider + '/status', + meta: { realmId: realmId }, + }, + { + onSuccess: () => { + notify(record.id + ` disabled successfully`, { + type: 'warning', + }); + refresh(); + }, + onError: error => { + const msg = + error && typeof error === 'object' && 'message' in error + ? (error['message'] as string) + : 'ra.error.http_error'; + + notify(msg, { + type: 'error', + }); + }, + } + ); + const [enable] = useUpdate( + 'idps', + { + id: record.provider + '/status', + data: record, + meta: { realmId: realmId }, + }, + { + onSuccess: () => { + notify(record.id + ` enabled successfully`, { + type: 'success', + }); + refresh(); + }, + onError: error => { + const msg = + error && typeof error === 'object' && 'message' in error + ? (error['message'] as string) + : 'ra.error.http_error'; + + notify(msg, { + type: 'error', + }); + }, + } + ); + + if (!record) return null; + return ( + <> + {record.enabled && ( + + )} + {!record.enabled && ( + + )} + + ); +}; diff --git a/dev-console/src/idps/IdpIcon.tsx b/dev-console/src/idps/IdpIcon.tsx new file mode 100644 index 000000000..e84cd3b5d --- /dev/null +++ b/dev-console/src/idps/IdpIcon.tsx @@ -0,0 +1,2 @@ +import KeyIcon from '@mui/icons-material/Key'; +export const IdpIcon = KeyIcon; \ No newline at end of file diff --git a/dev-console/src/idps/IdpList.tsx b/dev-console/src/idps/IdpList.tsx new file mode 100644 index 000000000..5d5f37a0b --- /dev/null +++ b/dev-console/src/idps/IdpList.tsx @@ -0,0 +1,158 @@ +import { Box } from '@mui/material'; + +import { isValidElement, ReactElement } from 'react'; +import { + Datagrid, + List, + SearchInput, + TopToolbar, + useRecordContext, + ExportButton, + useTranslate, + BooleanField, + FunctionField, +} from 'react-admin'; +import { YamlExporter } from '../components/YamlExporter'; +import { useRootSelector } from '@dslab/ra-root-selector'; +import { IdpCreateForm } from './IdpCreate'; +import { CreateInDialogButton } from '@dslab/ra-dialog-crud'; +import { ActionsButtons } from '../components/ActionsButtons'; +import { IdField } from '../components/IdField'; +import { PageTitle } from '../components/PageTitle'; +import { Page } from '../components/Page'; +import { NameField } from '../components/NameField'; +import { IdpIcon } from './IdpIcon'; +import { getIdpIcon } from './utils'; +import EnabledIcon from '@mui/icons-material/CheckCircleOutlined'; +import DisabledIcon from '@mui/icons-material/CancelOutlined'; +import RegisteredIcon from '@mui/icons-material/VerifiedUser'; +import WarningIcon from '@mui/icons-material/WarningOutlined'; + +export const IdpList = () => { + const translate = useTranslate(); + return ( + + + } + filters={ListFilters} + sort={{ field: 'name', order: 'ASC' }} + component={Box} + empty={false} + > + + + + ); +}; + +export const IdpListView = (props: { actions?: ReactElement | boolean }) => { + const { actions: actionProps = true } = props; + + const actions = !actionProps ? ( + false + ) : isValidElement(actionProps) ? ( + actionProps + ) : ( + + ); + + return ( + + + + + + { + if (!record.enabled) return <>; + return ( + + ); + }} + /> + {actions !== false && actions} + + ); +}; + +export const IdpNameField = (props: { source: string; label?: string }) => { + const { label } = props; + const record = useRecordContext(); + const color = record?.registered + ? 'primary' + : record?.enabled + ? 'warning' + : 'info'; + + const iconColor = record?.registered + ? 'primary' + : record?.enabled + ? 'error' + : 'disabled'; + + const icon = record ? ( + getIdpIcon(record.authority, { + color: iconColor, + }) + ) : ( + + ); + + return ( + + ); +}; + +const ListFilters = []; + +const ListActions = () => { + const { root: realmId } = useRootSelector(); + const transform = (data: any) => { + return { + ...data, + type: 'identity', + realm: realmId, + }; + }; + + return ( + + + + + + + ); +}; diff --git a/dev-console/src/idps/index.tsx b/dev-console/src/idps/index.tsx new file mode 100644 index 000000000..c2cbe1342 --- /dev/null +++ b/dev-console/src/idps/index.tsx @@ -0,0 +1,11 @@ +import { IdpEdit } from './IdpEdit'; +import { IdpIcon } from './IdpIcon'; +import { IdpList } from './IdpList'; + +export default { + name: 'idps', + list: IdpList, + edit: IdpEdit, + icon: IdpIcon, + recordRepresentation: record => record.name, +}; diff --git a/dev-console/src/idps/schemas.ts b/dev-console/src/idps/schemas.ts new file mode 100644 index 000000000..d28716a83 --- /dev/null +++ b/dev-console/src/idps/schemas.ts @@ -0,0 +1,299 @@ +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +export const getIdpSchema = (schema?: any) => { + if (!schema) { + return {}; + } + + //fix id definition + //TODO update in backend + if ('id' in schema) { + schema['$id'] = schema['id']; + delete schema['id']; + } + + return schema; +}; + +export const getIdpUiSchema = (schema?: any) => { + if (!schema || (!('$id' in schema) && !('id' in schema))) { + return {}; + } + + const type = schema['$id'] || schema['id']; + let uiSchema = {}; + if (type in idpUiSchemas) { + uiSchema = { ...idpUiSchemas[type] }; + } + + //inject titles if missing + if (schema) { + for (const p in schema.properties) { + if (!(p in uiSchema)) { + uiSchema[p] = {}; + } + + if (!('ui:title' in uiSchema[p])) { + uiSchema[p]['ui:title'] = + schema.properties[p].title || 'field.' + p + '.name'; + } + if (!('ui:description' in uiSchema[p])) { + uiSchema[p]['ui:description'] = + schema.properties[p].description || + 'field.' + p + '.helperText'; + } + } + } + + return uiSchema; +}; + +export const schemaIdpSettings: RJSFSchema = { + type: 'object', + properties: { + template: { + type: 'string', + title: 'field.template_override.name', + description: 'field.template_override.helperText', + }, + events: { + type: 'string', + enum: ['none', 'minimal', 'details', 'full'], + default: 'minimal', + title: 'field.events.name', + description: 'field.events.helperText', + }, + persistence: { + type: 'string', + enum: ['none', 'repository', 'session'], + default: 'repository', + title: 'field.persistence.name', + description: 'field.persistence.helperText', + }, + position: { + type: ['number', 'null'], + default: null, + title: 'field.position.name', + description: 'field.position.helperText', + }, + linkable: { + type: 'boolean', + title: 'field.linkable.name', + description: 'field.linkable.helperText', + }, + notes: { + type: 'string', + title: 'field.notes.name', + description: 'field.notes.helperText', + }, + }, +}; + +export const uiSchemaIdpSettings: UiSchema = { + 'ui:layout': [12], +}; + +export const uiSchemaInternalIdp: UiSchema = { + 'ui:layout': [4, 4, 4], + 'ui:order': [ + 'enableRegistration', + 'enableDelete', + 'enableUpdate', + 'maxSessionDuration', + 'confirmationRequired', + 'confirmationValidity', + ], +}; +export const uiSchemaAppleIdp: UiSchema = { + 'ui:layout': [6, 6, 12, 12, 4, 4, 4], + privateKey: { + 'ui:widget': 'textarea', + }, +}; +export const uiSchemaOidcIdp: UiSchema = { + 'ui:layout': [ + 12, 12, 12, 12, 6, 6, 12, 6, 6, 4, 4, 4, 12, 12, 12, 12, 12, 6, 6, + ], + clientJwk: { + 'ui:widget': 'textarea', + }, +}; +export const uiSchemaPasswordIdp: UiSchema = { + 'ui:layout': [12, 12, 12, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 6, 6], + 'ui:order': [ + 'displayAsButton', + 'requireAccountConfirmation', + 'maxSessionDuration', + 'repositoryId', + 'enablePasswordReset', + 'passwordResetValidity', + 'passwordMinLength', + 'passwordMaxLength', + 'passwordRequireAlpha', + 'passwordRequireUppercaseAlpha', + 'passwordRequireNumber', + 'passwordRequireSpecial', + 'passwordSupportWhitespace', + 'passwordKeepNumber', + 'passwordMaxDays', + ], + repositoryId: { + 'ui:widget': 'hidden', + }, +}; + +export const uiSchemaWebAuthnIdp: UiSchema = { + 'ui:layout': [12], +}; + +export const uiSchemaSamlIdp: UiSchema = { + 'ui:layout': [ + 12, 6, 6, 6, 6, 12, 12, 6, 6, 6, 6, 12, 6, 6, 8, 4, 8, 12, 4, 4, 4, 6, + 6, + ], + 'ui:order': [ + 'entityId', + 'signingKey', + 'signingCertificate', + 'cryptKey', + 'cryptCertificate', + 'idpMetadataUrl', + 'idpEntityId', + 'webSsoUrl', + 'webLogoutUrl', + + 'ssoServiceBinding', + 'signAuthNRequest', + + 'verificationCertificate', + 'forceAuthn', + 'isPassive', + + 'nameIDFormat', + 'nameIDAllowCreate', + + 'authnContextClasses', + 'authnContextComparison', + + 'trustEmailAddress', + 'alwaysTrustEmailAddress', + 'requireEmailAddress', + + 'userNameAttributeName', + 'subAttributeName', + ], + signingKey: { + 'ui:widget': 'textarea', + }, + signingCertificate: { + 'ui:widget': 'textarea', + }, + cryptKey: { + 'ui:widget': 'textarea', + }, + cryptCertificate: { + 'ui:widget': 'textarea', + }, + authnContextClasses: { + items: { + 'ui:label': false, + }, + }, +}; + +export const uiSchemaOpenidfedIdp: UiSchema = { + 'ui:layout': [ + 6, 6, 12, 12, 12, 12, 4, 4, 4, 12, 12, 12, 12, 12, 12, 12, 12, 12, 6, 6, + 6, 6, + ], + 'ui:order': [ + 'clientId', + 'clientName', + 'clientJwks', + 'federationJwks', + + 'scope', + 'claims', + + 'trustEmailAddress', + 'requireEmailAddress', + 'alwaysTrustEmailAddress', + + 'organizationName', + 'contacts', + 'trustAnchor', + 'providers', + 'authorityHints', + 'trustMarks', + + 'acrValues', + 'respectTokenExpiration', + 'promptMode', + 'userNameAttributeName', + 'subjectType', + 'userInfoJWEAlg', + 'userInfoJWEEnc', + ], + clientJwks: { + 'ui:widget': 'textarea', + }, + federationJwks: { + 'ui:widget': 'textarea', + }, +}; +export const uiSchemaSpidIdp: UiSchema = { + 'ui:layout': [12, 6, 6, 6, 6, 12, 6, 6, 6, 6, 12, 12, 12, 12, 6, 6], + 'ui:order': [ + 'entityId', + 'signingKey', + 'signingCertificate', + 'organizationDisplayName', + 'organizationName', + 'organizationUrl', + 'contactPerson_EmailAddress', + 'contactPerson_Type', + 'contactPerson_IPACode', + 'contactPerson_Public', + 'idps', + 'idpMetadataUrl', + 'spidAttributes', + 'authnContext', + 'subAttributeName', + 'usernameAttributeName', + ], + signingKey: { + 'ui:widget': 'textarea', + }, + signingCertificate: { + 'ui:widget': 'textarea', + }, + spidAttributes: { + items: { + 'ui:label': false, + }, + }, + authnContext: { + 'ui:title': 'field.spidLevel.name', + 'ui:description': 'field.spidLevel.helperText', + }, +}; +//list + +export const idpUiSchemas = { + 'urn:jsonschema:it:smartcommunitylab:aac:internal:provider:InternalIdentityProviderConfigMap': + uiSchemaInternalIdp, + 'urn:jsonschema:it:smartcommunitylab:aac:password:provider:PasswordIdentityProviderConfigMap': + uiSchemaPasswordIdp, + 'urn:jsonschema:it:smartcommunitylab:aac:oidc:apple:provider:AppleIdentityProviderConfigMap': + uiSchemaAppleIdp, + 'urn:jsonschema:it:smartcommunitylab:aac:oidc:provider:OIDCIdentityProviderConfigMap': + uiSchemaOidcIdp, + 'urn:jsonschema:it:smartcommunitylab:aac:openidfed:provider:OpenIdFedIdentityProviderConfigMap': + uiSchemaOpenidfedIdp, + 'urn:jsonschema:it:smartcommunitylab:aac:webauthn:provider:WebAuthnIdentityProviderConfigMap': + uiSchemaWebAuthnIdp, + 'urn:jsonschema:it:smartcommunitylab:aac:saml:provider:SamlIdentityProviderConfigMap': + uiSchemaSamlIdp, + 'urn:jsonschema:it:smartcommunitylab:aac:spid:provider:SpidIdentityProviderConfigMap': + uiSchemaSpidIdp, +}; diff --git a/dev-console/src/idps/utils.tsx b/dev-console/src/idps/utils.tsx new file mode 100644 index 000000000..5d0a6d030 --- /dev/null +++ b/dev-console/src/idps/utils.tsx @@ -0,0 +1,52 @@ +import React from 'react'; + +import { IdpIcon } from './IdpIcon'; +import AppleIcon from '@mui/icons-material/Apple'; +import LockPersonIcon from '@mui/icons-material/LockPerson'; +import PasswordIcon from '@mui/icons-material/Password'; +import GitHubIcon from '@mui/icons-material/GitHub'; +import GoogleIcon from '@mui/icons-material/Google'; +import FacebookIcon from '@mui/icons-material/Facebook'; +import VpnKeyIcon from '@mui/icons-material/VpnKey'; +import AssuredWorkloadIcon from '@mui/icons-material/AssuredWorkload'; +import BusinessIcon from '@mui/icons-material/Business'; +import { SvgIconOwnProps } from '@mui/material'; +import LocalPoliceIcon from '@mui/icons-material/LocalPolice'; + +export const AppleIdpIcon = AppleIcon; +export const InternalIdpIcon = LockPersonIcon; +export const PasswordIdpIcon = PasswordIcon; +export const GithubIdpIcon = GitHubIcon; +export const FacebookIdpIcon = FacebookIcon; +export const GoogleIdpIcon = GoogleIcon; +export const SamlIdpIcon = BusinessIcon; +export const OidcIdpIcon = AssuredWorkloadIcon; +export const WebAuthnIdpIcon = VpnKeyIcon; +export const OpenIdFedIcon = LocalPoliceIcon; +export const SpidIcon = LocalPoliceIcon; + +export const authorities = { + apple: { icon: AppleIdpIcon }, + internal: { icon: InternalIdpIcon }, + password: { icon: PasswordIdpIcon }, + github: { icon: GithubIdpIcon }, + facebook: { icon: FacebookIdpIcon }, + saml: { icon: SamlIdpIcon }, + webauthn: { icon: WebAuthnIdpIcon }, + google: { icon: GoogleIdpIcon }, + oidc: { icon: OidcIdpIcon }, + openidfed: { icon: OpenIdFedIcon }, + spid: { icon: SpidIcon }, +}; + +export const getIdpIcon = (authority?: string, props?: SvgIconOwnProps) => { + if (!authority) { + return ; + } + + if (authority in authorities) { + return React.createElement(authorities[authority].icon, props); + } + + return ; +}; diff --git a/dev-console/src/index.css b/dev-console/src/index.css new file mode 100644 index 000000000..4b326a5a4 --- /dev/null +++ b/dev-console/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', + 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', + 'Helvetica Neue', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/dev-console/src/index.tsx b/dev-console/src/index.tsx new file mode 100644 index 000000000..30a6dae89 --- /dev/null +++ b/dev-console/src/index.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import './index.css'; +import { App } from './App'; +import { Spacer } from './components/Spacer'; + +const root = ReactDOM.createRoot( + document.getElementById('root') as HTMLElement +); +root.render( + + + + +); diff --git a/dev-console/src/layout/AppLayout.tsx b/dev-console/src/layout/AppLayout.tsx new file mode 100644 index 000000000..2756c6b79 --- /dev/null +++ b/dev-console/src/layout/AppLayout.tsx @@ -0,0 +1,119 @@ +import { + AppBar, + AppBarProps, + Layout, + useGetIdentity, + useTranslate, +} from 'react-admin'; +import { Typography } from '@mui/material'; +import { FunctionComponent } from 'react'; +import { Logout, UserMenu } from 'react-admin'; +import MenuItem from '@mui/material/MenuItem'; +import { MenuItemProps } from '@mui/material/MenuItem'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemText from '@mui/material/ListItemText'; +import DeveloperModeIcon from '@mui/icons-material/DeveloperMode'; +import SettingsIcon from '@mui/icons-material/Settings'; +import AccountBoxIcon from '@mui/icons-material/AccountBox'; +import React from 'react'; + +import { RootResourceSelectorMenu } from '@dslab/ra-root-selector'; +import { MyMenu } from './MyMenu'; + +const ACCOUNT_URL: string = process.env.REACT_APP_USER_CONSOLE as string; +const ADMIN_URL: string = process.env.REACT_APP_ADMIN_CONSOLE as string; + +const AccountMenu: FunctionComponent> = React.forwardRef( + function MenuToAccount(props, ref) { + const translate = useTranslate(); + const isXSmall = false; + const handleClick = () => { + window.location.href = ACCOUNT_URL; + return; + }; + return ( + + + + + {translate('account')} + + ); + } +); + +const AdminMenu: FunctionComponent> = React.forwardRef( + function MenuToAdmin(props, ref) { + const translate = useTranslate(); + const isXSmall = false; + const handleClick = () => { + window.location.href = ADMIN_URL; + return; + }; + return ( + + + + + {translate('admin')} + + ); + } +); + +const MyUserMenu = () => { + const { data } = useGetIdentity(); + + const isDeveloper = + data && + data.authorities.find( + (r: any) => + r.role && + (r.role === 'ROLE_DEVELOPER' || r.role === 'ROLE_ADMIN') + ); + const isAdmin = + data && data.authorities.find((r: any) => r.authority === 'ROLE_ADMIN'); + + return ( + + {isDeveloper && } + {isAdmin && } + + + ); +}; + +const MyAppBar = (props: AppBarProps) => { + return ( + }> + + + + + ); +}; + +const AppLayout = (props: any) => ( + +); + +export default AppLayout; diff --git a/dev-console/src/layout/MyMenu.tsx b/dev-console/src/layout/MyMenu.tsx new file mode 100644 index 000000000..38f40a449 --- /dev/null +++ b/dev-console/src/layout/MyMenu.tsx @@ -0,0 +1,102 @@ +import { useRootSelector } from '@dslab/ra-root-selector'; +import { + Accordion, + AccordionDetails, + AccordionSummary, + Box, + Divider, +} from '@mui/material'; +import { + useBasename, + useGetResourceLabel, + Menu, + MenuItemLink, + useTranslate, + useCreatePath, +} from 'react-admin'; +import { RealmIcon } from '../myrealms/RealmIcon'; +import SettingsIcon from '@mui/icons-material/Settings'; +import { ReactElement } from 'react'; +import { AppIcon } from '../apps/AppIcon'; +import { UserIcon } from '../users/UserIcon'; +import { IdpIcon } from '../idps/IdpIcon'; +import { AttributeSetIcon } from '../attributeset/AttributeSetIcon'; +import { RoleIcon } from '../roles/RoleIcon'; + +const defaultIcon = ; + +const MenuEntries = (props: { + children: ReactElement | ReactElement[]; + label: string; + icon?: ReactElement; +}) => { + const { label, children, icon = defaultIcon } = props; + const translate = useTranslate(); + + return ( + + + + {translate(label)} + + + {children} + + ); +}; + +export const MyMenu = () => { + const basename = useBasename(); + const getResourceLabel = useGetResourceLabel(); + const { base, root: realmId } = useRootSelector(); + const createPath = useCreatePath(); + + return ( + + + + {/* apps */} + + + {/* users */} + + + {/* authentication */} + + {/* authorization */} + + + {/* attributes */} + + + + + + } + to={createPath({ + resource: 'myrealms', + id: realmId, + type: 'edit', + })} + primaryText={'menu.configuration'} + /> + } + to={base || '/'} + primaryText={<>{getResourceLabel('myrealms', 2)}} + selected={false} + /> + + + ); +}; diff --git a/dev-console/src/logo.svg b/dev-console/src/logo.svg new file mode 100644 index 000000000..fd873b35a --- /dev/null +++ b/dev-console/src/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dev-console/src/myrealms/RealmCreate.tsx b/dev-console/src/myrealms/RealmCreate.tsx new file mode 100644 index 000000000..5586d925a --- /dev/null +++ b/dev-console/src/myrealms/RealmCreate.tsx @@ -0,0 +1,47 @@ +import { + BooleanInput, + Form, + minLength, + SaveButton, + TextInput, +} from 'react-admin'; +import { DialogActions, Stack } from '@mui/material'; +import { Page } from '../components/Page'; + +export const RealmCreateForm = () => { + return ( +
+ + + + + + + + + + + + +
+ ); +}; diff --git a/dev-console/src/myrealms/RealmEdit.tsx b/dev-console/src/myrealms/RealmEdit.tsx new file mode 100644 index 000000000..0750a1831 --- /dev/null +++ b/dev-console/src/myrealms/RealmEdit.tsx @@ -0,0 +1,197 @@ +import { Alert, Box } from '@mui/material'; +import { + BooleanInput, + Edit, + List, + SaveButton, + TabbedForm, + TextInput, + Toolbar, + TopToolbar, + useRecordContext, + useTranslate, +} from 'react-admin'; +import { InspectButton } from '@dslab/ra-inspect-button'; +import { DeleteWithDialogButton } from '@dslab/ra-delete-dialog-button'; +import { Page } from '../components/Page'; +import { SectionTitle } from '../components/SectionTitle'; +import { RefreshingExportButton } from '../components/RefreshingExportButton'; +import { ResourceTitle } from '../components/ResourceTitle'; +import SettingsIcon from '@mui/icons-material/Settings'; +import { + realmLocalizationSchema, + realmOAuthSchema, + realmTosSchema, +} from './schemas'; +import { JsonSchemaInput } from '@dslab/ra-jsonschema-input'; +import WarningIcon from '@mui/icons-material/WarningOutlined'; +import { + DeveloperListActions, + DeveloperListView, +} from '../developers/DeveloperList'; +import { AceEditorInput } from '@dslab/ra-ace-editor'; + +export const RealmEdit = () => { + return ( + + } + mutationMode="optimistic" + component={Box} + redirect={'edit'} + > + + } + /> + + + + ); +}; + +const RealmEditForm = () => { + const translate = useTranslate(); + const record = useRecordContext(); + if (!record) return null; + + if (!record.editable) { + return ( + }> + {translate('error.not_editable')} + + ); + } + + return ( + } syncWithLocation={false}> + + + + + + + + + + + + + + + + + + + + + + + + + + } + sort={{ field: 'name', order: 'ASC' }} + component={Box} + empty={false} + disableSyncWithLocation + storeKey={false} + > + + + + + ); +}; + +const ActionsToolbar = () => { + const record = useRecordContext(); + if (!record || !record.editable) return null; + + return ( + + + + + + ); +}; + +const TabToolbar = () => ( + + + +); diff --git a/dev-console/src/myrealms/RealmIcon.tsx b/dev-console/src/myrealms/RealmIcon.tsx new file mode 100644 index 000000000..df4e93fc7 --- /dev/null +++ b/dev-console/src/myrealms/RealmIcon.tsx @@ -0,0 +1,3 @@ +import LayersIcon from '@mui/icons-material/Layers'; + +export const RealmIcon = LayersIcon; \ No newline at end of file diff --git a/dev-console/src/myrealms/RealmList.tsx b/dev-console/src/myrealms/RealmList.tsx new file mode 100644 index 000000000..35472d632 --- /dev/null +++ b/dev-console/src/myrealms/RealmList.tsx @@ -0,0 +1,154 @@ +import { + List, + SearchInput, + Datagrid, + TopToolbar, + useTranslate, + NumberField, + ExportButton, + ListView, + DeleteWithConfirmButton, + useRecordContext, +} from 'react-admin'; +import { Box, Stack } from '@mui/material'; +import { YamlExporter } from '../components/YamlExporter'; + +import React, { isValidElement, ReactElement } from 'react'; +import { + RootSelectorButton, + RootSelectorListProps, + useRootSelector, +} from '@dslab/ra-root-selector'; +import { RealmCreateForm } from './RealmCreate'; +import { + CreateInDialogButton, + EditInDialogButton, +} from '@dslab/ra-dialog-crud'; +import { PageTitle } from '../components/PageTitle'; +import { ActionsButtons } from '../components/ActionsButtons'; +import { IdField } from '../components/IdField'; +import { RealmIcon } from './RealmIcon'; +import { NameField } from '../components/NameField'; +import { Page } from '../components/Page'; +import { + DeleteWithConfirmDialog, + DeleteWithDialogButton, +} from '@dslab/ra-delete-dialog-button'; +import { RowButtonGroup } from '../components/RowButtonGroup'; + +export const RealmList = () => { + const translate = useTranslate(); + return ( + + + } + filters={RealmFilters} + sort={{ field: 'name', order: 'ASC' }} + component={Box} + empty={false} + > + + + + ); +}; +export const RealmSelectorList = (props: RootSelectorListProps) => { + const translate = useTranslate(); + return ( + + + } + filters={RealmFilters} + sort={{ field: 'name', order: 'ASC' }} + component={Box} + empty={false} + > + } /> + + + ); +}; +export const RealmListView = (props: { actions?: ReactElement | boolean }) => { + const { actions: actionProps = true } = props; + const { selectRoot } = useRootSelector(); + const actions = !actionProps ? ( + false + ) : isValidElement(actionProps) ? ( + actionProps + ) : ( + + ); + + return ( + { + selectRoot(record); + return false; + }} + > + } + /> + + {actions !== false && actions} + + ); +}; + +const RealmSelectorActions = () => { + const record = useRecordContext(); + return ( + + + + {record?.editable && ( + + + + )} + {record?.editable && ( + + )} + + + ); +}; + +const RealmFilters = []; + +const RealmListActions = () => { + const { root: realmId } = useRootSelector(); + const transform = (data: any) => { + return { + ...data, + realm: realmId, + }; + }; + + return ( + + + + + + ); +}; diff --git a/dev-console/src/myrealms/index.tsx b/dev-console/src/myrealms/index.tsx new file mode 100644 index 000000000..dc61a6237 --- /dev/null +++ b/dev-console/src/myrealms/index.tsx @@ -0,0 +1,12 @@ +import { RealmEdit } from './RealmEdit'; +import { RealmIcon } from './RealmIcon'; +import { RealmList, RealmSelectorList } from './RealmList'; + +export default { + name: 'myrealms', + list: RealmList, + edit: RealmEdit, + icon: RealmIcon, + recordRepresentation: record => record.slug, + selector: RealmSelectorList, +}; diff --git a/dev-console/src/myrealms/schemas.ts b/dev-console/src/myrealms/schemas.ts new file mode 100644 index 000000000..79fea0c26 --- /dev/null +++ b/dev-console/src/myrealms/schemas.ts @@ -0,0 +1,61 @@ +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +export const realmLocalizationSchema: RJSFSchema = { + type: 'object', + properties: { + languages: { + type: 'array', + uniqueItems: true, + items: { + type: 'string', + enum: ['en', 'it', 'de', 'es', 'lv'], + }, + default: [], + title: 'field.languages.name', + description: 'field.languages.helperText', + }, + }, +}; + +export const realmTemplatesSchema: RJSFSchema = { + type: 'object', + properties: { + customStyle: { + type: ['string', 'null'], + default: null, + title: 'field.customStyle.name', + description: 'field.customStyle.helperText', + }, + }, +}; + +export const realmOAuthSchema: RJSFSchema = { + type: 'object', + properties: { + enableClientRegistration: { + type: 'boolean', + title: 'field.oauth2.enableClientRegistration.name', + description: 'field.oauth2.enableClientRegistration.helperText', + }, + openClientRegistration: { + type: 'boolean', + title: 'field.oauth2.openClientRegistration.name', + description: 'field.oauth2.openClientRegistration.helperText', + }, + }, +}; +export const realmTosSchema: RJSFSchema = { + type: 'object', + properties: { + enableTOS: { + type: 'boolean', + title: 'field.tos.enableTOS.name', + description: 'field.tos.enableTOS.helperText', + }, + approveTOS: { + type: 'boolean', + title: 'field.tos.approveTOS.name', + description: 'field.tos.approveTOS.helperText', + }, + }, +}; diff --git a/dev-console/src/pages/dashboard.tsx b/dev-console/src/pages/dashboard.tsx new file mode 100644 index 000000000..1a9023a05 --- /dev/null +++ b/dev-console/src/pages/dashboard.tsx @@ -0,0 +1,231 @@ +import { + Button, + useCreatePath, + useDataProvider, + useGetIdentity, + useGetResourceLabel, + useTranslate, +} from 'react-admin'; +import LinearProgress from '@mui/material/LinearProgress'; +import { Box, Typography } from '@mui/material'; +import { Grid, Avatar } from '@mui/material'; +import { PageTitle } from '../components/PageTitle'; +import { useRootSelector } from '@dslab/ra-root-selector'; +import { useEffect, useState } from 'react'; +import { Page } from '../components/Page'; +import { DashboardCard } from '../components/cards'; +import UserLoginIcon from '@mui/icons-material/LoginOutlined'; +import UserRegistrationIcon from '@mui/icons-material/HowToRegOutlined'; +import TokenIcon from '@mui/icons-material/Token'; +import ContentAddIcon from '@mui/icons-material/AddBoxOutlined'; +import { Link } from 'react-router-dom'; + +const DevDashboard = () => { + const { data: user, isLoading } = useGetIdentity(); + const { root: realmId } = useRootSelector(); + const translate = useTranslate(); + const dataProvider = useDataProvider(); + + const [stats, setStats] = useState(null); + + useEffect(() => { + let loading = true; + dataProvider + .invoke({ path: 'realms/' + realmId + '/stats' }) + .then(data => { + if (data) { + setStats(data); + } + }); + + return () => { + loading = false; + }; + }, [dataProvider]); + + if (isLoading === true || !user || !stats || !dataProvider) { + return ; + } + + return ( + + + {stats.realm.name.substring(0, 2)} + + ) + } + /> + + + + + } + /> + + + + + } + /> + + + + } + /> + + + + + + {stats.apps && stats.apps > 0 ? ( + + ) : ( + } + to={false} + /> + )} + + + {stats.users && stats.users > 0 ? ( + + ) : ( + } + to={false} + /> + )} + + + {stats.providers && stats.providers > 0 ? ( + + ) : ( + } + to={false} + /> + )} + + + {stats.services && stats.services > 0 ? ( + + ) : ( + } + to={false} + /> + )} + + + + ); +}; + +const Empty = (props: { resource: string }) => { + const { resource } = props; + const createPath = useCreatePath(); + const translate = useTranslate(); + + const getResourceLabel = useGetResourceLabel(); + const resourceName = translate(`resources.${resource}.forcedCaseName`, { + smart_count: 0, + _: getResourceLabel(resource, 0), + }); + + const emptyMessage = translate('ra.page.empty', { name: resourceName }); + const inviteMessage = translate('ra.page.invite'); + + const to = createPath({ resource: resource, type: 'list' }); + + return ( + <> + + + {translate(`resources.${resource}.empty`, { + _: emptyMessage, + })} + + + + {translate(`resources.${resource}.invite`, { + _: inviteMessage, + })} + + + + ) : ( + + )} + + ); +}; + +export const VerifyButton = (props: { reference: string }) => { + const { reference } = props; + const record = useRecordContext(); + const resource = useResourceContext(); + const dataProvider = useDataProvider(); + const { root: realmId } = useRootSelector(); + const notify = useNotify(); + const refresh = useRefresh(); + + const handleClick = () => { + if (dataProvider && record) { + dataProvider + .invoke({ + path: + 'users/' + + realmId + + '/' + + reference + + '/account/' + + record.id + + '/confirm', + body: JSON.stringify({}), + options: { + method: 'POST', + }, + }) + .then(() => { + notify('ra.notification.updated', { + messageArgs: { smart_count: 1 }, + }); + refresh(); + }); + } + }; + + if (!record || !record.email) return null; + return ( + + ); +}; + +export const ToggleConfirmButton = (props: { reference: string }) => { + const { reference } = props; + const record = useRecordContext(); + const resource = useResourceContext(); + const dataProvider = useDataProvider(); + const { root: realmId } = useRootSelector(); + const notify = useNotify(); + const refresh = useRefresh(); + + const handleClick = action => { + if (dataProvider && record) { + dataProvider + .invoke({ + path: + 'users/' + + realmId + + '/' + + reference + + '/account/' + + record.id + + '/confirm', + body: JSON.stringify({}), + options: { + method: action, + }, + }) + .then(() => { + notify('ra.notification.updated', { + messageArgs: { smart_count: 1 }, + }); + refresh(); + }); + } + }; + + if (!record || !record.email) return null; + return ( + <> + {record.confirmed === false ? ( + + ) : ( + + )} + + ); +}; diff --git a/dev-console/src/users/UserCreate.tsx b/dev-console/src/users/UserCreate.tsx new file mode 100644 index 000000000..d38449250 --- /dev/null +++ b/dev-console/src/users/UserCreate.tsx @@ -0,0 +1,45 @@ +import { CreateBase, Form, SaveButton, TextInput, Toolbar } from 'react-admin'; +import { Card, CardContent, Box, Divider, Typography } from '@mui/material'; + +export const UserCreate = () => { + const transform = (data: any) => { + return { + ...data, + }; + }; + + return ; +}; +export const UserCreateForm = () => { + return ( + <> + Invite user + + +
+ + + + + + + + + + + + + + + + + +
+
+
+ + ); +}; diff --git a/dev-console/src/users/UserEdit.tsx b/dev-console/src/users/UserEdit.tsx new file mode 100644 index 000000000..b4ecef52a --- /dev/null +++ b/dev-console/src/users/UserEdit.tsx @@ -0,0 +1,331 @@ +import { Avatar, Box, Typography } from '@mui/material'; +import { + ArrayField, + AutocompleteArrayInput, + BooleanField, + Button, + Datagrid, + Edit, + IconButtonWithTooltip, + Labeled, + ReferenceArrayInput, + ReferenceManyField, + TabbedForm, + TextField, + Toolbar, + TopToolbar, + useDataProvider, + useGetList, + useNotify, + useRecordContext, + useRefresh, + useResourceContext, + useTranslate, +} from 'react-admin'; +import { DeleteWithDialogButton } from '@dslab/ra-delete-dialog-button'; +import { InspectButton } from '@dslab/ra-inspect-button'; +import { Page } from '../components/Page'; +import { AuthoritiesDialogButton } from '../components/AuthoritiesDialog'; +import { RefreshingExportButton } from '../components/RefreshingExportButton'; +import { useRootSelector } from '@dslab/ra-root-selector'; +import { AuditListView } from '../audit/AuditList'; +import { IdField } from '../components/IdField'; +import { ResourceTitle } from '../components/ResourceTitle'; +import { SectionTitle } from '../components/SectionTitle'; +import { DeveloperIcon, AdminIcon } from '../developers/DeveloperIcon'; +import { ConnectedApps } from './ConnectedApps'; +import { useWatch } from 'react-hook-form'; +import ContentSave from '@mui/icons-material/Save'; +import { NameField } from '../components/NameField'; +import { DataGridBlankHeader } from '../components/DataGridBlankHeader'; +import VerifiedUserIcon from '@mui/icons-material/VerifiedUser'; +import EnabledIcon from '@mui/icons-material/CheckCircleOutlined'; +import WarningIcon from '@mui/icons-material/WarningOutlined'; +import GppBadIcon from '@mui/icons-material/GppBad'; +import { UserAccountsForm } from './UserAccounts'; +import LockIcon from '@mui/icons-material/Lock'; +import LockOpenIcon from '@mui/icons-material/LockOpen'; +import { ReferencedArrayInput } from '../components/ReferencedArrayInput'; + +export const UserEdit = () => { + return ( + + } + mutationMode="pessimistic" + component={Box} + redirect={'edit'} + queryOptions={{ meta: { flatten: ['roles', 'groups'] } }} + > + } icon={} /> + + + + ); +}; + +const UserTitle = () => { + const record = useRecordContext(); + if (!record) return null; + + return ( + + {record.username}{' '} + {record.status === 'active' ? ( + + + + ) : ( + + + + )} + {record.emailVerified === true ? ( + + + + ) : ( + + + + )} + {record.authorities.find(r => r.role === 'ROLE_DEVELOPER') && ( + + + + )} + {record.authorities.find(r => r.role === 'ROLE_ADMIN') && ( + + + + )} + + ); +}; + +const UserAvatar = () => { + const record = useRecordContext(); + if (!record) return null; + + return ( + + {record.username.toUpperCase().substring(0, 2)} + + ); +}; + +const UserForm = () => { + const record = useRecordContext(); + const translate = useTranslate(); + + if (!record) return null; + + return ( + ({ error: 'not editable' })} + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } + > + + + + + +
+
+ + + } + > + + + + + +
+ + + + + + + + + + + + +
+ ); +}; + +const EditToolBarActions = () => { + const refresh = useRefresh(); + const record = useRecordContext(); + + if (!record) return null; + + return ( + + + + refresh()} /> + + + + ); +}; + +export const ToggleUserStatusButton = () => { + const record = useRecordContext(); + const dataProvider = useDataProvider(); + const { root: realmId } = useRootSelector(); + const notify = useNotify(); + const refresh = useRefresh(); + + const handleStatus = status => { + if (dataProvider && record) { + dataProvider + .invoke({ + path: 'users/' + realmId + '/' + record.id + '/status', + body: JSON.stringify({ status }), + options: { + method: 'PUT', + }, + }) + .then(() => { + notify('ra.notification.updated', { + messageArgs: { smart_count: 1 }, + }); + refresh(); + }); + } + }; + + if (!record) return null; + return ( + <> + {record.status === 'active' ? ( + + ) : ( + + )} + + ); +}; diff --git a/dev-console/src/users/UserIcon.tsx b/dev-console/src/users/UserIcon.tsx new file mode 100644 index 000000000..8b52ff5d3 --- /dev/null +++ b/dev-console/src/users/UserIcon.tsx @@ -0,0 +1,2 @@ +import PersonIcon from '@mui/icons-material/Person'; +export const UserIcon = PersonIcon; \ No newline at end of file diff --git a/dev-console/src/users/UserList.tsx b/dev-console/src/users/UserList.tsx new file mode 100644 index 000000000..a1c6de10e --- /dev/null +++ b/dev-console/src/users/UserList.tsx @@ -0,0 +1,92 @@ +import { Box } from '@mui/material'; +import { + List, + Datagrid, + TopToolbar, + SearchInput, + useTranslate, + ExportButton, +} from 'react-admin'; +import { CreateInDialogButton } from '@dslab/ra-dialog-crud'; +import { UserCreateForm } from './UserCreate'; +import { Page } from '../components/Page'; +import { PageTitle } from '../components/PageTitle'; +import { YamlExporter } from '../components/YamlExporter'; +import { IdField } from '../components/IdField'; +import { isValidElement, ReactElement } from 'react'; +import { ActionsButtons } from '../components/ActionsButtons'; +import { NameField } from '../components/NameField'; +import { TagsField } from '../components/TagsField'; + +export const UserList = () => { + const translate = useTranslate(); + return ( + + + } + filters={UserFilters} + sort={{ field: 'username', order: 'ASC' }} + component={Box} + > + + + + ); +}; + +export const UserListView = (props: { actions?: ReactElement | boolean }) => { + const { actions: actionProps = true } = props; + + const actions = !actionProps ? ( + false + ) : isValidElement(actionProps) ? ( + actionProps + ) : ( + + ); + + return ( + + + + + {actions !== false && actions} + + ); +}; + +const UserFilters = []; + +const UserListActions = () => { + return ( + + + + + + + ); +}; + +const transform = (data: any) => { + return { + ...data, + }; +}; diff --git a/dev-console/src/users/activeButton.tsx b/dev-console/src/users/activeButton.tsx new file mode 100644 index 000000000..9b57310ed --- /dev/null +++ b/dev-console/src/users/activeButton.tsx @@ -0,0 +1,60 @@ +import { useRecordContext, useNotify, useRefresh, useUpdate, Button } from "react-admin"; +import BlockIcon from '@mui/icons-material/Block'; +import PlayArrowIcon from '@mui/icons-material/PlayArrow'; +export const ActiveButton = () => { + const record = useRecordContext(); + const notify = useNotify(); + const refresh = useRefresh(); + const [inactive] = useUpdate( + 'users', + { + id: record.id + '/status', + data: record, + }, + { + onSuccess: () => { + notify(`user ` + record.id + ` disabled successfully`); + refresh(); + }, + } + ); + const [active] = useUpdate( + 'users', + { + id: record.id + '/status', + data: record, + }, + { + onSuccess: () => { + notify(`user ` + record.id + ` enabled successfully`); + refresh(); + }, + } + ); + + if (!record) return null; + return ( + <> + {record.status !== 'inactive' && ( + + )} + {record.status === 'inactive' && ( + + )} + + ); +}; \ No newline at end of file diff --git a/dev-console/src/users/index.tsx b/dev-console/src/users/index.tsx new file mode 100644 index 000000000..643ba4d97 --- /dev/null +++ b/dev-console/src/users/index.tsx @@ -0,0 +1,13 @@ +import { UserCreate } from './UserCreate'; +import { UserEdit } from './UserEdit'; +import { UserIcon } from './UserIcon'; +import { UserList } from './UserList'; + +export default { + name: 'users', + list: UserList, + create: UserCreate, + edit: UserEdit, + icon: UserIcon, + recordRepresentation: record => record.username, +}; diff --git a/dev-console/src/utils.ts b/dev-console/src/utils.ts new file mode 100644 index 000000000..de46fdb87 --- /dev/null +++ b/dev-console/src/utils.ts @@ -0,0 +1,39 @@ +export class utils { + public static parseBase64(source: string): string | null { + try { + return atob(source || ''); + } catch (e: any) { + // console.log('p', e); + return null; + } + } + + public static encodeBase64(source: string): string | null { + try { + return source ? btoa(source) : null; + } catch (e: any) { + return null; + } + } + + //deep copy an obj with nested props + public static deepCopy(source: T): T { + return Array.isArray(source) + ? source.map(i => this.deepCopy(i)) + : source && typeof source === 'object' + ? Object.getOwnPropertyNames(source).reduce((obj, prop) => { + Object.defineProperty( + obj, + prop, + Object.getOwnPropertyDescriptor(source, prop)! + ); + obj[prop] = this.deepCopy( + (source as { [key: string]: any })[prop] + ); + return obj; + }, Object.create(Object.getPrototypeOf(source))) + : (source as T); + } +} + +export default utils; diff --git a/dev-console/src/vite-env.d.ts b/dev-console/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/dev-console/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/dev-console/tsconfig.json b/dev-console/tsconfig.json new file mode 100644 index 000000000..9b46f98f8 --- /dev/null +++ b/dev-console/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "noImplicitAny":false + }, + "include": [ + "src" +, "**/*.tsx" ] +} diff --git a/dev-console/vite.config.ts b/dev-console/vite.config.ts new file mode 100644 index 000000000..abcbc9271 --- /dev/null +++ b/dev-console/vite.config.ts @@ -0,0 +1,23 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import { splitVendorChunkPlugin } from 'vite'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), splitVendorChunkPlugin()], + define: { + 'process.env': process.env, + }, + server: { + host: true, + }, + base: '/console/dev/', + build: { + manifest: true, + commonjsOptions: { transformMixedEsModules: true }, + }, + optimizeDeps: { + include: ['@mui/material/Tooltip'], + exclude: ['js-big-decimal'], + }, +}); diff --git a/dev-console/yarn.lock b/dev-console/yarn.lock new file mode 100644 index 000000000..766a9408f --- /dev/null +++ b/dev-console/yarn.lock @@ -0,0 +1,4840 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@adobe/css-tools@^4.0.1": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.4.0.tgz#728c484f4e10df03d5a3acd0d8adcbbebff8ad63" + integrity sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ== + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" + integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== + dependencies: + "@babel/highlight" "^7.24.7" + picocolors "^1.0.0" + +"@babel/compat-data@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.7.tgz#d23bbea508c3883ba8251fb4164982c36ea577ed" + integrity sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw== + +"@babel/core@^7.24.5": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.7.tgz#b676450141e0b52a3d43bc91da86aa608f950ac4" + integrity sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.24.7" + "@babel/helper-compilation-targets" "^7.24.7" + "@babel/helper-module-transforms" "^7.24.7" + "@babel/helpers" "^7.24.7" + "@babel/parser" "^7.24.7" + "@babel/template" "^7.24.7" + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.7.tgz#1654d01de20ad66b4b4d99c135471bc654c55e6d" + integrity sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA== + dependencies: + "@babel/types" "^7.24.7" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz#4eb6c4a80d6ffeac25ab8cd9a21b5dfa48d503a9" + integrity sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg== + dependencies: + "@babel/compat-data" "^7.24.7" + "@babel/helper-validator-option" "^7.24.7" + browserslist "^4.22.2" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" + integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-function-name@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz#75f1e1725742f39ac6584ee0b16d94513da38dd2" + integrity sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA== + dependencies: + "@babel/template" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-hoist-variables@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz#b4ede1cde2fd89436397f30dc9376ee06b0f25ee" + integrity sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" + integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-module-transforms@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz#31b6c9a2930679498db65b685b1698bfd6c7daf8" + integrity sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ== + dependencies: + "@babel/helper-environment-visitor" "^7.24.7" + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-simple-access" "^7.24.7" + "@babel/helper-split-export-declaration" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + +"@babel/helper-plugin-utils@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz#98c84fe6fe3d0d3ae7bfc3a5e166a46844feb2a0" + integrity sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg== + +"@babel/helper-simple-access@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" + integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-split-export-declaration@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz#83949436890e07fa3d6873c61a96e3bbf692d856" + integrity sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-string-parser@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz#4d2d0f14820ede3b9807ea5fc36dfc8cd7da07f2" + integrity sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg== + +"@babel/helper-validator-identifier@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + +"@babel/helper-validator-option@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz#24c3bb77c7a425d1742eec8fb433b5a1b38e62f6" + integrity sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw== + +"@babel/helpers@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.7.tgz#aa2ccda29f62185acb5d42fb4a3a1b1082107416" + integrity sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg== + dependencies: + "@babel/template" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/highlight@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" + integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== + dependencies: + "@babel/helper-validator-identifier" "^7.24.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" + integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== + +"@babel/plugin-transform-react-jsx-self@^7.24.5": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz#66bff0248ea0b549972e733516ffad577477bdab" + integrity sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/plugin-transform-react-jsx-source@^7.24.1": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.7.tgz#1198aab2548ad19582013815c938d3ebd8291ee3" + integrity sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.8", "@babel/runtime@^7.23.9", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12" + integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/runtime@^7.3.1": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.8.tgz#5d958c3827b13cc6d05e038c07fb2e5e3420d82e" + integrity sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/template@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315" + integrity sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/parser" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/traverse@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.7.tgz#de2b900163fa741721ba382163fe46a936c40cf5" + integrity sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.24.7" + "@babel/helper-environment-visitor" "^7.24.7" + "@babel/helper-function-name" "^7.24.7" + "@babel/helper-hoist-variables" "^7.24.7" + "@babel/helper-split-export-declaration" "^7.24.7" + "@babel/parser" "^7.24.7" + "@babel/types" "^7.24.7" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.7.tgz#6027fe12bc1aa724cd32ab113fb7f1988f1f66f2" + integrity sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q== + dependencies: + "@babel/helper-string-parser" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + to-fast-properties "^2.0.0" + +"@dslab/ra-ace-editor@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@dslab/ra-ace-editor/-/ra-ace-editor-1.1.0.tgz#077db12019cfcfac18392386400ac5aacde3d753" + integrity sha512-ZuRQfno4hVuhnoyHvpiSqPQ4PwooWRbm7F5vRp1bPFCgQcbScl74ejsDflWeVpXVIfWK3dIxlAfXBErx4Ym8HA== + dependencies: + ace-builds "^1.14.0" + react-ace "^10.1.0" + +"@dslab/ra-datagrid-input@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@dslab/ra-datagrid-input/-/ra-datagrid-input-1.0.0.tgz#0a60c60952ee3c77d3cbac66df76ccebd67925e5" + integrity sha512-SYhaHkDnigOCYdkbr19Ri0o+MEF2kefLGM2sX1p4L6ePgD6j/7PoT/xzzk4BYkwOB1knb3fnsRqUzw1Q8a7IVw== + dependencies: + ra-core "^4.11.0" + +"@dslab/ra-delete-dialog-button@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@dslab/ra-delete-dialog-button/-/ra-delete-dialog-button-1.0.0.tgz#ddb3c71d0ae1dc30259d4a45d7117259c33546ee" + integrity sha512-I04u517k/sn7RSMYViVA5nunNERJBV85WAIi8KMlkBcKcuOEzpDBDeqXPJK9RYB+ZKWLxOkEcO/ypFifqabsEQ== + dependencies: + ra-core "^4.11.0" + +"@dslab/ra-dialog-crud@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@dslab/ra-dialog-crud/-/ra-dialog-crud-1.0.2.tgz#108f1ba013d6ecddd1406c002b62888236d926a2" + integrity sha512-e097ycgeg9ww9RZ9oNGyk0zCtPc3RGyhKg7naAswFvDITwYoZasE84nGkliIEmgy50hXbP6WxUhW4QBzhLI5kQ== + dependencies: + ra-core "^4.11.0" + +"@dslab/ra-export-record-button@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@dslab/ra-export-record-button/-/ra-export-record-button-1.0.0.tgz#395c5dace51626a2cd98fa713c05cc2b9b2fb77e" + integrity sha512-5xcpyrAjWMhKXHdvFznlFh6mm0InxlICxF8Qlik4lO5/hdmhlifmpLm6Sjw8ePb0DZrEReCEM6kuBCmODDq29A== + dependencies: + ra-core "^4.11.0" + yaml "^2.3.4" + +"@dslab/ra-inspect-button@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@dslab/ra-inspect-button/-/ra-inspect-button-1.0.3.tgz#c7bb9c949da8b8b0505b84e25a6402b2624f5fe7" + integrity sha512-GDdcPkbWZe/hL0bN4wNSsjAtW0xb0G3J47Ectr5iADARWmCimmmnrnvVAzuUm6fH6KP/enRKs1YBxzEl+f99ig== + dependencies: + ra-core "^4.11.0" + react-syntax-highlighter "^15.5.0" + yaml "^2.3.4" + +"@dslab/ra-jsonschema-input@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@dslab/ra-jsonschema-input/-/ra-jsonschema-input-2.1.1.tgz#a4227075408d19355b7e7a1d873d3f364a5333ab" + integrity sha512-YrtC7etPyIcV7xLK/0SByv2cxVsnrabQI/ayrH8JSMZnPV7L0jGZFtHf7zjGn7P8Uz9bMDTmwVJAW/ypoRUf3Q== + dependencies: + "@rjsf/core" "^5.18.2" + "@rjsf/mui" "^5.18.2" + "@rjsf/utils" "^5.18.2" + "@rjsf/validator-ajv8" "^5.18.2" + ajv "^8.12.0" + ajv-formats "^2.1.1" + +"@dslab/ra-language-italian@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@dslab/ra-language-italian/-/ra-language-italian-1.0.2.tgz#60c84e50764c2b46b29dd17a00bd81c267724cfa" + integrity sha512-efoSrVn/XxFN4SgEQK/YbUfCBQBGsBqerl2y//QLusqHqJgRG2EUdG1/85smEF2tt8wXMcnBSwi5pqQFZk3o7Q== + dependencies: + ra-core "^4.11.0" + +"@dslab/ra-root-selector@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@dslab/ra-root-selector/-/ra-root-selector-1.0.3.tgz#7300bed38fd3ab72c0dc1d6e307b5ec30710a552" + integrity sha512-H4iUD4h22szr+f5rX0RJIjb50aal9WHgWOu0KTNkYATOpo6cdlEsLPnAQi018B579VInso/KN6C3NnJ3BseDWQ== + dependencies: + ra-core "^4.11.0" + +"@dslab/ra-stepper@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@dslab/ra-stepper/-/ra-stepper-1.1.1.tgz#d9404eebe8a192cb37a1839f92332611bf92673d" + integrity sha512-CrgbzioCvemqHLcku0Jy/SOLZd/l5dHtXh8iEekGpY8eOsPZ+coPBWSoXYz8lzdATpe48RVFTYQIMviio6J95w== + dependencies: + ra-core "^4.11.0" + +"@emotion/babel-plugin@^11.11.0": + version "11.11.0" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c" + integrity sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/runtime" "^7.18.3" + "@emotion/hash" "^0.9.1" + "@emotion/memoize" "^0.8.1" + "@emotion/serialize" "^1.1.2" + babel-plugin-macros "^3.1.0" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.2.0" + +"@emotion/cache@^11.11.0": + version "11.11.0" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.11.0.tgz#809b33ee6b1cb1a625fef7a45bc568ccd9b8f3ff" + integrity sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ== + dependencies: + "@emotion/memoize" "^0.8.1" + "@emotion/sheet" "^1.2.2" + "@emotion/utils" "^1.2.1" + "@emotion/weak-memoize" "^0.3.1" + stylis "4.2.0" + +"@emotion/hash@^0.9.1": + version "0.9.1" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43" + integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ== + +"@emotion/is-prop-valid@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz#d4175076679c6a26faa92b03bb786f9e52612337" + integrity sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw== + dependencies: + "@emotion/memoize" "^0.8.1" + +"@emotion/memoize@^0.8.1": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17" + integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== + +"@emotion/react@^11.4.1": + version "11.11.4" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.4.tgz#3a829cac25c1f00e126408fab7f891f00ecc3c1d" + integrity sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.11.0" + "@emotion/cache" "^11.11.0" + "@emotion/serialize" "^1.1.3" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" + "@emotion/utils" "^1.2.1" + "@emotion/weak-memoize" "^0.3.1" + hoist-non-react-statics "^3.3.1" + +"@emotion/serialize@^1.1.2", "@emotion/serialize@^1.1.3", "@emotion/serialize@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.4.tgz#fc8f6d80c492cfa08801d544a05331d1cc7cd451" + integrity sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ== + dependencies: + "@emotion/hash" "^0.9.1" + "@emotion/memoize" "^0.8.1" + "@emotion/unitless" "^0.8.1" + "@emotion/utils" "^1.2.1" + csstype "^3.0.2" + +"@emotion/sheet@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec" + integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== + +"@emotion/styled@^11.3.0": + version "11.11.5" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.11.5.tgz#0c5c8febef9d86e8a926e663b2e5488705545dfb" + integrity sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.11.0" + "@emotion/is-prop-valid" "^1.2.2" + "@emotion/serialize" "^1.1.4" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" + "@emotion/utils" "^1.2.1" + +"@emotion/unitless@^0.8.1": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3" + integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ== + +"@emotion/use-insertion-effect-with-fallbacks@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz#08de79f54eb3406f9daaf77c76e35313da963963" + integrity sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw== + +"@emotion/utils@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4" + integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg== + +"@emotion/weak-memoize@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" + integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== + +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" + integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.57.0": + version "8.57.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" + integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== + +"@floating-ui/core@^1.6.0": + version "1.6.4" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.4.tgz#0140cf5091c8dee602bff9da5ab330840ff91df6" + integrity sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA== + dependencies: + "@floating-ui/utils" "^0.2.4" + +"@floating-ui/dom@^1.0.0": + version "1.6.7" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.7.tgz#85d22f731fcc5b209db504478fb1df5116a83015" + integrity sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng== + dependencies: + "@floating-ui/core" "^1.6.0" + "@floating-ui/utils" "^0.2.4" + +"@floating-ui/react-dom@^2.0.8": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.1.tgz#cca58b6b04fc92b4c39288252e285e0422291fb0" + integrity sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg== + dependencies: + "@floating-ui/dom" "^1.0.0" + +"@floating-ui/utils@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.4.tgz#1d459cee5031893a08a0e064c406ad2130cced7c" + integrity sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA== + +"@gfx/zopfli@^1.0.15": + version "1.0.15" + resolved "https://registry.yarnpkg.com/@gfx/zopfli/-/zopfli-1.0.15.tgz#00720b4f6a4d5ceeb585a5d6dd672b48bd4fc755" + integrity sha512-7mBgpi7UD82fsff5ThQKet0uBTl4BYerQuc+/qA1ELTwWEiIedRTcD3JgiUu9wwZ2kytW8JOb165rSdAt8PfcQ== + dependencies: + base64-js "^1.3.0" + +"@humanwhocodes/config-array@^0.11.14": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== + dependencies: + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@mui/base@5.0.0-beta.40": + version "5.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.40.tgz#1f8a782f1fbf3f84a961e954c8176b187de3dae2" + integrity sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ== + dependencies: + "@babel/runtime" "^7.23.9" + "@floating-ui/react-dom" "^2.0.8" + "@mui/types" "^7.2.14" + "@mui/utils" "^5.15.14" + "@popperjs/core" "^2.11.8" + clsx "^2.1.0" + prop-types "^15.8.1" + +"@mui/core-downloads-tracker@^5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.0.tgz#50153c698e321793c83a0283d8d7a9dc5d43858a" + integrity sha512-8SLffXYPRVpcZx5QzxNE8fytTqzp+IuU3deZbQWg/vSaTlDpR5YVrQ4qQtXTi5cRdhOufV5INylmwlKK+//nPw== + +"@mui/icons-material@^5.0.1", "@mui/icons-material@^5.11.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.16.0.tgz#5269fda922fe5e6db3577ec497e8b987195606ef" + integrity sha512-6ISoOhkp9w5gD0PEW9JklrcbyARDkFWNTBdwXZ1Oy5IGlyu9B0zG0hnUIe4H17IaF1Vgj6C8VI+v4tkSdK0veg== + dependencies: + "@babel/runtime" "^7.23.9" + +"@mui/material@^5.0.2", "@mui/material@^5.11.7": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.16.0.tgz#2ef4f52ae773574fc0a681f25705f376f5cd13f7" + integrity sha512-DbR1NckTLpjt9Zut9EGQ70th86HfN0BYQgyYro6aXQrNfjzSwe3BJS1AyBQ5mJ7TdL6YVRqohfukxj9JlqZZUg== + dependencies: + "@babel/runtime" "^7.23.9" + "@mui/base" "5.0.0-beta.40" + "@mui/core-downloads-tracker" "^5.16.0" + "@mui/system" "^5.16.0" + "@mui/types" "^7.2.14" + "@mui/utils" "^5.16.0" + "@types/react-transition-group" "^4.4.10" + clsx "^2.1.0" + csstype "^3.1.3" + prop-types "^15.8.1" + react-is "^18.2.0" + react-transition-group "^4.4.5" + +"@mui/private-theming@^5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.16.0.tgz#c1abfd3e0d9c95459048240ef4209dc7f25dc949" + integrity sha512-sYpubkO1MZOnxNyVOClrPNOTs0MfuRVVnAvCeMaOaXt6GimgQbnUcshYv2pSr6PFj+Mqzdff/FYOBceK8u5QgA== + dependencies: + "@babel/runtime" "^7.23.9" + "@mui/utils" "^5.16.0" + prop-types "^15.8.1" + +"@mui/styled-engine@^5.15.14": + version "5.15.14" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.15.14.tgz#168b154c4327fa4ccc1933a498331d53f61c0de2" + integrity sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw== + dependencies: + "@babel/runtime" "^7.23.9" + "@emotion/cache" "^11.11.0" + csstype "^3.1.3" + prop-types "^15.8.1" + +"@mui/system@^5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.16.0.tgz#e5b4cfbdfbc0ee9859f6b168e8b07d750303b7a0" + integrity sha512-9YbkC2m3+pNumAvubYv+ijLtog6puJ0fJ6rYfzfLCM47pWrw3m+30nXNM8zMgDaKL6vpfWJcCXm+LPaWBpy7sw== + dependencies: + "@babel/runtime" "^7.23.9" + "@mui/private-theming" "^5.16.0" + "@mui/styled-engine" "^5.15.14" + "@mui/types" "^7.2.14" + "@mui/utils" "^5.16.0" + clsx "^2.1.0" + csstype "^3.1.3" + prop-types "^15.8.1" + +"@mui/types@^7.2.14": + version "7.2.14" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.14.tgz#8a02ac129b70f3d82f2f9b76ded2c8d48e3fc8c9" + integrity sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ== + +"@mui/utils@^5.15.14", "@mui/utils@^5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.16.0.tgz#3963127d9a619c251e5be1aef9adab0e89d3e7df" + integrity sha512-kLLi5J1xY+mwtUlMb8Ubdxf4qFAA1+U7WPBvjM/qQ4CIwLCohNb0sHo1oYPufjSIH/Z9+dhVxD7dJlfGjd1AVA== + dependencies: + "@babel/runtime" "^7.23.9" + "@types/prop-types" "^15.7.11" + prop-types "^15.8.1" + react-is "^18.2.0" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@popperjs/core@^2.11.8", "@popperjs/core@^2.9.0": + version "2.11.8" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" + integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== + +"@remirror/core-constants@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@remirror/core-constants/-/core-constants-2.0.2.tgz#f05eccdc69e3a65e7d524b52548f567904a11a1a" + integrity sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ== + +"@remix-run/router@1.17.1": + version "1.17.1" + resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.17.1.tgz#bf93997beb81863fde042ebd05013a2618471362" + integrity sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q== + +"@rjsf/core@^5.18.2": + version "5.19.3" + resolved "https://registry.yarnpkg.com/@rjsf/core/-/core-5.19.3.tgz#34d476f0ec9d25fd838e374c861acb9ee9860c25" + integrity sha512-AAzolj+fcFlwk0/5THA7T2JkmYTIUa+fLPM5prFqPw55FwWOa0qC5zIOfkhPS95Z9bfwJv3BubOAiKZ7MOGe8Q== + dependencies: + lodash "^4.17.21" + lodash-es "^4.17.21" + markdown-to-jsx "^7.4.1" + nanoid "^3.3.7" + prop-types "^15.8.1" + +"@rjsf/mui@^5.18.2": + version "5.19.3" + resolved "https://registry.yarnpkg.com/@rjsf/mui/-/mui-5.19.3.tgz#b81e9c03c493090910f6ffce203455a737750664" + integrity sha512-8H8+JITEwaS4mw/wLroI9OLijs4bBuEO1qpqhgiugLMjX+8ar3ehVN7luSkamGykliQH5Gp1I978dGIzzV2wmw== + +"@rjsf/utils@^5.18.2": + version "5.19.3" + resolved "https://registry.yarnpkg.com/@rjsf/utils/-/utils-5.19.3.tgz#776ae78610af61a7e1de1149e158e0bc4a1e45bd" + integrity sha512-1lG/uMMmnAJE48BHUl4laNY2W2j2gIR2LH4jsxeEMSuFloB06ZuUXLesD03Nz2zQjm66izNmnm5eAmAi3Pa1yQ== + dependencies: + json-schema-merge-allof "^0.8.1" + jsonpointer "^5.0.1" + lodash "^4.17.21" + lodash-es "^4.17.21" + react-is "^18.2.0" + +"@rjsf/validator-ajv8@^5.18.2": + version "5.19.3" + resolved "https://registry.yarnpkg.com/@rjsf/validator-ajv8/-/validator-ajv8-5.19.3.tgz#924b12f4ada82b9750dfdb3853e6c4b98afce579" + integrity sha512-ah0DY1tGmBDNd0iIjH9/iL3TSflriY8cYPmAwK4aDzGLnwHgD2w8sEfJJjG01pX89rY2CeeYxcwCalwlBlUZ/w== + dependencies: + ajv "^8.12.0" + ajv-formats "^2.1.1" + lodash "^4.17.21" + lodash-es "^4.17.21" + +"@rollup/rollup-android-arm-eabi@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.1.tgz#f0da481244b7d9ea15296b35f7fe39cd81157396" + integrity sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA== + +"@rollup/rollup-android-arm64@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.1.tgz#82ab3c575f4235fb647abea5e08eec6cf325964e" + integrity sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg== + +"@rollup/rollup-darwin-arm64@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.1.tgz#6a530452e68a9152809ce58de1f89597632a085b" + integrity sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ== + +"@rollup/rollup-darwin-x64@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.1.tgz#47727479f5ca292cf434d7e75af2725b724ecbc7" + integrity sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA== + +"@rollup/rollup-linux-arm-gnueabihf@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.1.tgz#46193c498aa7902a8db89ac00128060320e84fef" + integrity sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g== + +"@rollup/rollup-linux-arm-musleabihf@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.1.tgz#22d831fe239643c1d05c98906420325cee439d85" + integrity sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ== + +"@rollup/rollup-linux-arm64-gnu@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.1.tgz#19abd33695ec9d588b4a858d122631433084e4a3" + integrity sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ== + +"@rollup/rollup-linux-arm64-musl@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.1.tgz#d60af8c0b9be424424ff96a0ba19fce65d26f6ab" + integrity sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ== + +"@rollup/rollup-linux-powerpc64le-gnu@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.1.tgz#b1194e5ed6d138fdde0842d126fccde74a90f457" + integrity sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ== + +"@rollup/rollup-linux-riscv64-gnu@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.1.tgz#f5a635c017b9bff8b856b0221fbd5c0e3373b7ec" + integrity sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg== + +"@rollup/rollup-linux-s390x-gnu@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.1.tgz#f1043d9f4026bf6995863cb3f8dd4732606e4baa" + integrity sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg== + +"@rollup/rollup-linux-x64-gnu@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.1.tgz#1e781730be445119f06c9df5f185e193bc82c610" + integrity sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g== + +"@rollup/rollup-linux-x64-musl@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.1.tgz#08f12e1965d6f27d6898ff932592121cca6abc4b" + integrity sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ== + +"@rollup/rollup-win32-arm64-msvc@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.1.tgz#4a5dcbbe7af7d41cac92b09798e7c1831da1f599" + integrity sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g== + +"@rollup/rollup-win32-ia32-msvc@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.1.tgz#075b0713de627843a73b4cf0e087c56b53e9d780" + integrity sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg== + +"@rollup/rollup-win32-x64-msvc@4.18.1": + version "4.18.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.1.tgz#0cb240c147c0dfd0e3eaff4cc060a772d39e155c" + integrity sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw== + +"@simplewebauthn/browser@^7.0.1": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@simplewebauthn/browser/-/browser-7.4.0.tgz#3e25b5e9f45d03eb60d3e4f8812d8d2acfd7dba6" + integrity sha512-qqCZ99lFWjtyza8NCtCpRm3GU5u8/QFeBfMgW5+U/E8Qyc4lvUcuJ8JTbrhksVQLZWSY1c/6Xw11QZ5e+D1hNw== + dependencies: + "@simplewebauthn/typescript-types" "^7.4.0" + +"@simplewebauthn/typescript-types@^7.0.0", "@simplewebauthn/typescript-types@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@simplewebauthn/typescript-types/-/typescript-types-7.4.0.tgz#1f5d55e187cbd30727a75543caf1bade747625ce" + integrity sha512-8/ZjHeUPe210Bt5oyaOIGx4h8lHdsQs19BiOT44gi/jBEgK7uBGA0Fy7NRsyh777al3m6WM0mBf0UR7xd4R7WQ== + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@testing-library/dom@^8.5.0": + version "8.20.1" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.20.1.tgz#2e52a32e46fc88369eef7eef634ac2a192decd9f" + integrity sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/runtime" "^7.12.5" + "@types/aria-query" "^5.0.1" + aria-query "5.1.3" + chalk "^4.1.0" + dom-accessibility-api "^0.5.9" + lz-string "^1.5.0" + pretty-format "^27.0.2" + +"@testing-library/jest-dom@^5.14.1": + version "5.17.0" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz#5e97c8f9a15ccf4656da00fecab505728de81e0c" + integrity sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg== + dependencies: + "@adobe/css-tools" "^4.0.1" + "@babel/runtime" "^7.9.2" + "@types/testing-library__jest-dom" "^5.9.1" + aria-query "^5.0.0" + chalk "^3.0.0" + css.escape "^1.5.1" + dom-accessibility-api "^0.5.6" + lodash "^4.17.15" + redent "^3.0.0" + +"@testing-library/react@^13.0.0": + version "13.4.0" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-13.4.0.tgz#6a31e3bf5951615593ad984e96b9e5e2d9380966" + integrity sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw== + dependencies: + "@babel/runtime" "^7.12.5" + "@testing-library/dom" "^8.5.0" + "@types/react-dom" "^18.0.0" + +"@testing-library/user-event@^13.2.1": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-13.5.0.tgz#69d77007f1e124d55314a2b73fd204b333b13295" + integrity sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg== + dependencies: + "@babel/runtime" "^7.12.5" + +"@tiptap/core@^2.0.3", "@tiptap/core@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.4.0.tgz#6f8eee8beb5b89363582366b201ccc4798ac98a9" + integrity sha512-YJSahk8pkxpCs8SflCZfTnJpE7IPyUWIylfgXM2DefjRQa5DZ+c6sNY0s/zbxKYFQ6AuHVX40r9pCfcqHChGxQ== + +"@tiptap/extension-blockquote@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.4.0.tgz#0179076ea2fa12e41a198dad087b81d368653b8d" + integrity sha512-nJJy4KsPgQqWTTDOWzFRdjCfG5+QExfZj44dulgDFNh+E66xhamnbM70PklllXJgEcge7xmT5oKM0gKls5XgFw== + +"@tiptap/extension-bold@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.4.0.tgz#b5ced2c3bf51f304890137dbdf394d58c01eb208" + integrity sha512-csnW6hMDEHoRfxcPRLSqeJn+j35Lgtt1YRiOwn7DlS66sAECGRuoGfCvQSPij0TCDp4VCR9if5Sf8EymhnQumQ== + +"@tiptap/extension-bubble-menu@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.4.0.tgz#a079329318fc21407f9a3c9c3da6ef72cb0b4ab6" + integrity sha512-s99HmttUtpW3rScWq8rqk4+CGCwergNZbHLTkF6Rp6TSboMwfp+rwL5Q/JkcAG9KGLso1vGyXKbt1xHOvm8zMw== + dependencies: + tippy.js "^6.3.7" + +"@tiptap/extension-bullet-list@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.4.0.tgz#60eea05b5ac8c8e8d615c057559fddb95033abeb" + integrity sha512-9S5DLIvFRBoExvmZ+/ErpTvs4Wf1yOEs8WXlKYUCcZssK7brTFj99XDwpHFA29HKDwma5q9UHhr2OB2o0JYAdw== + +"@tiptap/extension-code-block@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.4.0.tgz#b7f1da4825677a2ea6b8e970a1197877551e5dc8" + integrity sha512-QWGdv1D56TBGbbJSj2cIiXGJEKguPiAl9ONzJ/Ql1ZksiQsYwx0YHriXX6TOC//T4VIf6NSClHEtwtxWBQ/Csg== + +"@tiptap/extension-code@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.4.0.tgz#3a9fed3585bf49f445505c2e9ad71fd66e117304" + integrity sha512-wjhBukuiyJMq4cTcK3RBTzUPV24k5n1eEPlpmzku6ThwwkMdwynnMGMAmSF3fErh3AOyOUPoTTjgMYN2d10SJA== + +"@tiptap/extension-color@^2.0.3": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-2.4.0.tgz#eaddbd574953da85aaae9785269f2891b2d683ad" + integrity sha512-aVuqGtzTIZO93niADdu+Hx8g03X0pS7wjrJcCcYkkDEbC/siC03zlxKZIYBW1Jiabe99Z7/s2KdtLoK6DW2A2g== + +"@tiptap/extension-document@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.4.0.tgz#a396b2cbcc8708aa2a0a41d0be481fda4b61c77b" + integrity sha512-3jRodQJZDGbXlRPERaloS+IERg/VwzpC1IO6YSJR9jVIsBO6xC29P3cKTQlg1XO7p6ZH/0ksK73VC5BzzTwoHg== + +"@tiptap/extension-dropcursor@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.4.0.tgz#8f54908f84a4ab7d2d7de7fc0197511138445740" + integrity sha512-c46HoG2PEEpSZv5rmS5UX/lJ6/kP1iVO0Ax+6JrNfLEIiDULUoi20NqdjolEa38La2VhWvs+o20OviiTOKEE9g== + +"@tiptap/extension-floating-menu@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.4.0.tgz#75c48b98d0f833251eab70f269ed186f48fc398e" + integrity sha512-vLb9v+htbHhXyty0oaXjT3VC8St4xuGSHWUB9GuAJAQ+NajIO6rBPbLUmm9qM0Eh2zico5mpSD1Qtn5FM6xYzg== + dependencies: + tippy.js "^6.3.7" + +"@tiptap/extension-gapcursor@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.4.0.tgz#2a738509d40f5f856492c11e32b10e4462f71216" + integrity sha512-F4y/0J2lseohkFUw9P2OpKhrJ6dHz69ZScABUvcHxjznJLd6+0Zt7014Lw5PA8/m2d/w0fX8LZQ88pZr4quZPQ== + +"@tiptap/extension-hard-break@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.4.0.tgz#b5bf5b065827280e450fba8f53d137654509d836" + integrity sha512-3+Z6zxevtHza5IsDBZ4lZqvNR3Kvdqwxq/QKCKu9UhJN1DUjsg/l1Jn2NilSQ3NYkBYh2yJjT8CMo9pQIu776g== + +"@tiptap/extension-heading@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.4.0.tgz#16302ce691714244c3d3fa92d2db86a5c895a025" + integrity sha512-fYkyP/VMo7YHO76YVrUjd95Qeo0cubWn/Spavmwm1gLTHH/q7xMtbod2Z/F0wd6QHnc7+HGhO7XAjjKWDjldaw== + +"@tiptap/extension-highlight@^2.0.3": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.4.0.tgz#29a200993b0e599223efac373785089109579fd3" + integrity sha512-p2I/CaMrs6hzpj/dSw6UNobOWTV38yTjPK+B4ShJQ7IN2u/C82KOTOeFfJoFd9KykmpVOVW3w3nKG3ad0HXPuQ== + +"@tiptap/extension-history@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.4.0.tgz#1dbf8410c091175627414d48a0d857232a8f4094" + integrity sha512-gr5qsKAXEVGr1Lyk1598F7drTaEtAxqZiuuSwTCzZzkiwgEQsWMWTWc9F8FlneCEaqe1aIYg6WKWlmYPaFwr0w== + +"@tiptap/extension-horizontal-rule@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.4.0.tgz#7f27c0778004602686251af7e2f7a8461a3d77ba" + integrity sha512-yDgxy+YxagcEsBbdWvbQiXYxsv3noS1VTuGwc9G7ZK9xPmBHJ5y0agOkB7HskwsZvJHoaSqNRsh7oZTkf0VR3g== + +"@tiptap/extension-image@^2.0.3": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.4.0.tgz#21a18e80ed6bc330cf8ab2ca990a3addb40916c8" + integrity sha512-NIVhRPMO/ONo8OywEd+8zh0Q6Q7EbFHtBxVsvfOKj9KtZkaXQfUO4MzONTyptkvAchTpj9pIzeaEY5fyU87gFA== + +"@tiptap/extension-italic@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.4.0.tgz#42ab003e04e1e8d825f698914c0e80ac849144f1" + integrity sha512-aaW/L9q+KNHHK+X73MPloHeIsT191n3VLd3xm6uUcFDnUNvzYJ/q65/1ZicdtCaOLvTutxdrEvhbkrVREX6a8g== + +"@tiptap/extension-link@^2.0.3": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.4.0.tgz#e44edfe2f8d878959bd3ad64fda1b9e232f1f011" + integrity sha512-r3PjT0bjSKAorHAEBPA0icSMOlqALbxVlWU9vAc+Q3ndzt7ht0CTPNewzFF9kjzARABVt1cblXP/2+c0qGzcsg== + dependencies: + linkifyjs "^4.1.0" + +"@tiptap/extension-list-item@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.4.0.tgz#a97a48850b81e94b9a60cc2aa16e515aa5311456" + integrity sha512-reUVUx+2cI2NIAqMZhlJ9uK/+zvRzm1GTmlU2Wvzwc7AwLN4yemj6mBDsmBLEXAKPvitfLh6EkeHaruOGymQtg== + +"@tiptap/extension-ordered-list@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.4.0.tgz#6cf82e10d7e7f7cc44156d29b0b71a22dec31612" + integrity sha512-Zo0c9M0aowv+2+jExZiAvhCB83GZMjZsxywmuOrdUbq5EGYKb7q8hDyN3hkrktVHr9UPXdPAYTmLAHztTOHYRA== + +"@tiptap/extension-paragraph@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.4.0.tgz#5b9aea8775937b327bbe6754be12ae3144fb09ff" + integrity sha512-+yse0Ow67IRwcACd9K/CzBcxlpr9OFnmf0x9uqpaWt1eHck1sJnti6jrw5DVVkyEBHDh/cnkkV49gvctT/NyCw== + +"@tiptap/extension-placeholder@^2.0.3": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.4.0.tgz#b4cf5655cf6a4a39eaa5ef6a8376d5b31614db52" + integrity sha512-SmWOjgWpmhFt0BPOnL65abCUH0wS5yksUJgtANn5bQoHF4HFSsyl7ETRmgf0ykxdjc7tzOg31FfpWVH4wzKSYg== + +"@tiptap/extension-strike@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.4.0.tgz#f09c4f51f7fed01c356026d7e8d8a1d1f2ac8f18" + integrity sha512-pE1uN/fQPOMS3i+zxPYMmPmI3keubnR6ivwM+KdXWOMnBiHl9N4cNpJgq1n2eUUGKLurC2qrQHpnVyGAwBS6Vg== + +"@tiptap/extension-text-align@^2.0.3": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text-align/-/extension-text-align-2.4.0.tgz#15bda62a8f0d0feaede0632a15fb2d032ff81754" + integrity sha512-wpRe2OiLXTK4kTy4RZEPnPjFbK16kYHPAx1552hLXrOdyxbS7Sdbo+w4x7aGLLZZqZdudCFfkdtnqrc7PDVZdA== + +"@tiptap/extension-text-style@^2.0.3": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.4.0.tgz#9f86d8de4606bc37090b7b02c2aaf40bb37a860f" + integrity sha512-H0uPWeZ4sXz3o836TDWnpd38qClqzEM2d6QJ9TK+cQ1vE5Gp8wQ5W4fwUV1KAHzpJKE/15+BXBjLyVYQdmXDaQ== + +"@tiptap/extension-text@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.4.0.tgz#a3a5f45a9856d513e574f24e2c9b6028273f8eb3" + integrity sha512-LV0bvE+VowE8IgLca7pM8ll7quNH+AgEHRbSrsI3SHKDCYB9gTHMjWaAkgkUVaO1u0IfCrjnCLym/PqFKa+vvg== + +"@tiptap/extension-underline@^2.0.3": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.4.0.tgz#fb554333aed8a9ac1400b94f362a774c650f5a90" + integrity sha512-guWojb7JxUwLz4OKzwNExJwOkhZjgw/ttkXCMBT0PVe55k998MMYe1nvN0m2SeTW9IxurEPtScH4kYJ0XuSm8Q== + +"@tiptap/pm@^2.0.3": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.4.0.tgz#f6fe81d24569da584658d2e8a3a378aea3619fb3" + integrity sha512-B1HMEqGS4MzIVXnpgRZDLm30mxDWj51LkBT/if1XD+hj5gm8B9Q0c84bhvODX6KIs+c6z+zsY9VkVu8w9Yfgxg== + dependencies: + prosemirror-changeset "^2.2.1" + prosemirror-collab "^1.3.1" + prosemirror-commands "^1.5.2" + prosemirror-dropcursor "^1.8.1" + prosemirror-gapcursor "^1.3.2" + prosemirror-history "^1.3.2" + prosemirror-inputrules "^1.3.0" + prosemirror-keymap "^1.2.2" + prosemirror-markdown "^1.12.0" + prosemirror-menu "^1.2.4" + prosemirror-model "^1.19.4" + prosemirror-schema-basic "^1.2.2" + prosemirror-schema-list "^1.3.0" + prosemirror-state "^1.4.3" + prosemirror-tables "^1.3.5" + prosemirror-trailing-node "^2.0.7" + prosemirror-transform "^1.8.0" + prosemirror-view "^1.32.7" + +"@tiptap/react@^2.0.3": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.4.0.tgz#3d28944e10affa7aaf01bf291196dd9e27850e51" + integrity sha512-baxnIr6Dy+5iGagOEIKFeHzdl1ZRa6Cg+SJ3GDL/BVLpO6KiCM3Mm5ymB726UKP1w7icrBiQD2fGY3Bx8KaiSA== + dependencies: + "@tiptap/extension-bubble-menu" "^2.4.0" + "@tiptap/extension-floating-menu" "^2.4.0" + +"@tiptap/starter-kit@^2.0.3": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.4.0.tgz#ad2c2d900af41e55eaaccafa92fd6b2acaebd97e" + integrity sha512-DYYzMZdTEnRn9oZhKOeRCcB+TjhNz5icLlvJKoHoOGL9kCbuUyEf8WRR2OSPckI0+KUIPJL3oHRqO4SqSdTjfg== + dependencies: + "@tiptap/core" "^2.4.0" + "@tiptap/extension-blockquote" "^2.4.0" + "@tiptap/extension-bold" "^2.4.0" + "@tiptap/extension-bullet-list" "^2.4.0" + "@tiptap/extension-code" "^2.4.0" + "@tiptap/extension-code-block" "^2.4.0" + "@tiptap/extension-document" "^2.4.0" + "@tiptap/extension-dropcursor" "^2.4.0" + "@tiptap/extension-gapcursor" "^2.4.0" + "@tiptap/extension-hard-break" "^2.4.0" + "@tiptap/extension-heading" "^2.4.0" + "@tiptap/extension-history" "^2.4.0" + "@tiptap/extension-horizontal-rule" "^2.4.0" + "@tiptap/extension-italic" "^2.4.0" + "@tiptap/extension-list-item" "^2.4.0" + "@tiptap/extension-ordered-list" "^2.4.0" + "@tiptap/extension-paragraph" "^2.4.0" + "@tiptap/extension-strike" "^2.4.0" + "@tiptap/extension-text" "^2.4.0" + +"@types/aria-query@^5.0.1": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708" + integrity sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw== + +"@types/babel__core@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.8" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*": + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== + dependencies: + "@babel/types" "^7.20.7" + +"@types/estree@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + +"@types/hast@^2.0.0": + version "2.3.10" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.10.tgz#5c9d9e0b304bbb8879b857225c5ebab2d81d7643" + integrity sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw== + dependencies: + "@types/unist" "^2" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@*": + version "29.5.12" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.12.tgz#7f7dc6eb4cf246d2474ed78744b05d06ce025544" + integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/jest@^27.0.1": + version "27.5.2" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.5.2.tgz#ec49d29d926500ffb9fd22b84262e862049c026c" + integrity sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA== + dependencies: + jest-matcher-utils "^27.0.0" + pretty-format "^27.0.0" + +"@types/json-schema@^7.0.12": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/node@*": + version "20.14.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.10.tgz#a1a218290f1b6428682e3af044785e5874db469a" + integrity sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ== + dependencies: + undici-types "~5.26.4" + +"@types/node@^18.16.1": + version "18.19.39" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.39.tgz#c316340a5b4adca3aee9dcbf05de385978590593" + integrity sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ== + dependencies: + undici-types "~5.26.4" + +"@types/parse-json@^4.0.0": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" + integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== + +"@types/prop-types@*", "@types/prop-types@^15.7.11": + version "15.7.12" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" + integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== + +"@types/react-dom@^18.0.0", "@types/react-dom@^18.2.19": + version "18.3.0" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" + integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== + dependencies: + "@types/react" "*" + +"@types/react-transition-group@^4.4.10": + version "4.4.10" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac" + integrity sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^18.2.56": + version "18.3.3" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f" + integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + +"@types/semver@^7.5.0": + version "7.5.8" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" + integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== + +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/testing-library__jest-dom@^5.9.1": + version "5.14.9" + resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz#0fb1e6a0278d87b6737db55af5967570b67cb466" + integrity sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw== + dependencies: + "@types/jest" "*" + +"@types/unist@^2": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.10.tgz#04ffa7f406ab628f7f7e97ca23e290cd8ab15efc" + integrity sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA== + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.32" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" + integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.0.tgz#22bb999a8d59893c0ea07923e8a21f9d985ad740" + integrity sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "7.1.0" + "@typescript-eslint/type-utils" "7.1.0" + "@typescript-eslint/utils" "7.1.0" + "@typescript-eslint/visitor-keys" "7.1.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/parser@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.1.0.tgz#b89dab90840f7d2a926bf4c23b519576e8c31970" + integrity sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w== + dependencies: + "@typescript-eslint/scope-manager" "7.1.0" + "@typescript-eslint/types" "7.1.0" + "@typescript-eslint/typescript-estree" "7.1.0" + "@typescript-eslint/visitor-keys" "7.1.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz#e4babaa39a3d612eff0e3559f3e99c720a2b4a54" + integrity sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A== + dependencies: + "@typescript-eslint/types" "7.1.0" + "@typescript-eslint/visitor-keys" "7.1.0" + +"@typescript-eslint/type-utils@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz#372dfa470df181bcee0072db464dc778b75ed722" + integrity sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew== + dependencies: + "@typescript-eslint/typescript-estree" "7.1.0" + "@typescript-eslint/utils" "7.1.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/types@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.1.0.tgz#52a86d6236fda646e7e5fe61154991dc0dc433ef" + integrity sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA== + +"@typescript-eslint/typescript-estree@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz#419b1310f061feee6df676c5bed460537310c593" + integrity sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ== + dependencies: + "@typescript-eslint/types" "7.1.0" + "@typescript-eslint/visitor-keys" "7.1.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.1.0.tgz#710ecda62aff4a3c8140edabf3c5292d31111ddd" + integrity sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "7.1.0" + "@typescript-eslint/types" "7.1.0" + "@typescript-eslint/typescript-estree" "7.1.0" + semver "^7.5.4" + +"@typescript-eslint/visitor-keys@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz#576c4ad462ca1378135a55e2857d7aced96ce0a0" + integrity sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA== + dependencies: + "@typescript-eslint/types" "7.1.0" + eslint-visitor-keys "^3.4.1" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +"@vitejs/plugin-react@^4.2.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz#d0be6594051ded8957df555ff07a991fb618b48e" + integrity sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg== + dependencies: + "@babel/core" "^7.24.5" + "@babel/plugin-transform-react-jsx-self" "^7.24.5" + "@babel/plugin-transform-react-jsx-source" "^7.24.1" + "@types/babel__core" "^7.20.5" + react-refresh "^0.14.2" + +ace-builds@^1.14.0, ace-builds@^1.4.14: + version "1.35.2" + resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.35.2.tgz#2c26d2317ed8e378927e90e5c0d4fa17be92db79" + integrity sha512-06d00u4jDZx+ieI0jLlgy/uefx8kcgz7lhI0mCIFEu8NVWirH00U5IEP7tePHy4sjPsRcJUH4VbJZacoit2Hng== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.9.0: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.12.0: + version "8.16.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.16.0.tgz#22e2a92b94f005f7e0f9c9d39652ef0b8f6f0cb4" + integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw== + dependencies: + fast-deep-equal "^3.1.3" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.4.1" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +aria-query@5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" + integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== + dependencies: + deep-equal "^2.0.5" + +aria-query@^5.0.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" + integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== + dependencies: + dequal "^2.0.3" + +array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== + dependencies: + call-bind "^1.0.5" + is-array-buffer "^3.0.4" + +array-includes@^3.1.6, array-includes@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.findlast@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" + integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.flat@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.foreach@^1.0.2: + version "1.0.7" + resolved "https://registry.yarnpkg.com/array.prototype.foreach/-/array.prototype.foreach-1.0.7.tgz#e4bfbfb16ed9d9f04409e900ac85a7bb6a58f940" + integrity sha512-T6Y2wgc24suLW78a3Iq/Iu0zgucdBRtj11GElARgGZaqNC8ESFZV8qeJR9/I7bHCB3Vh5N6ATYUOBIZLLl9WCw== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-array-method-boxes-properly "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + is-string "^1.0.7" + +array.prototype.toreversed@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz#b989a6bf35c4c5051e1dc0325151bf8088954eba" + integrity sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.tosorted@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" + integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-shim-unscopables "^1.0.2" + +arraybuffer.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.2.1" + get-intrinsic "^1.2.3" + is-array-buffer "^3.0.4" + is-shared-array-buffer "^1.0.2" + +attr-accept@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" + integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== + +autosuggest-highlight@^3.1.1: + version "3.3.4" + resolved "https://registry.yarnpkg.com/autosuggest-highlight/-/autosuggest-highlight-3.3.4.tgz#d71b575ba8eab40b5adba73df9244e9ba88cc387" + integrity sha512-j6RETBD2xYnrVcoV1S5R4t3WxOlWZKyDQjkwnggDPSjF5L4jV98ZltBpvPvbkM1HtoSe5o+bNrTHyjPbieGeYA== + dependencies: + remove-accents "^0.4.2" + +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + +babel-plugin-macros@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" + integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== + dependencies: + "@babel/runtime" "^7.12.5" + cosmiconfig "^7.0.0" + resolve "^1.19.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +big-integer@^1.6.16: + version "1.6.52" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" + integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +broadcast-channel@^3.4.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937" + integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg== + dependencies: + "@babel/runtime" "^7.7.2" + detect-node "^2.1.0" + js-sha3 "0.8.0" + microseconds "0.2.0" + nano-time "1.0.0" + oblivious-set "1.0.0" + rimraf "3.0.2" + unload "2.2.0" + +browserslist@^4.22.2: + version "4.23.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.2.tgz#244fe803641f1c19c28c48c4b6ec9736eb3d32ed" + integrity sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA== + dependencies: + caniuse-lite "^1.0.30001640" + electron-to-chromium "^1.4.820" + node-releases "^2.0.14" + update-browserslist-db "^1.1.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +caniuse-lite@^1.0.30001640: + version "1.0.30001641" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001641.tgz#3572862cd18befae3f637f2a1101cc033c6782ac" + integrity sha512-Phv5thgl67bHYo1TtMY/MurjkHhV4EDaCosezRXgZ8jzA/Ub+wjxAvbGvjoFENStinwi5kCyOYV3mi5tOGykwA== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +clsx@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" + integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== + +clsx@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +comma-separated-tokens@^1.0.0: + version "1.0.8" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" + integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== + +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +commander@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +compute-gcd@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/compute-gcd/-/compute-gcd-1.2.1.tgz#34d639f3825625e1357ce81f0e456a6249d8c77f" + integrity sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg== + dependencies: + validate.io-array "^1.0.3" + validate.io-function "^1.0.2" + validate.io-integer-array "^1.0.0" + +compute-lcm@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/compute-lcm/-/compute-lcm-1.1.2.tgz#9107c66b9dca28cefb22b4ab4545caac4034af23" + integrity sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ== + dependencies: + compute-gcd "^1.2.1" + validate.io-array "^1.0.3" + validate.io-function "^1.0.2" + validate.io-integer-array "^1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^1.5.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cosmiconfig@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" + integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +crelt@^1.0.0: + version "1.0.6" + resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72" + integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g== + +cross-spawn@^7.0.0, cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-mediaquery@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0" + integrity sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q== + +css.escape@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" + integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== + +csstype@^3.0.2, csstype@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +date-fns@^2.19.0: + version "2.30.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" + integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== + dependencies: + "@babel/runtime" "^7.21.0" + +debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.5" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + +decode-uri-component@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== + +deep-equal@^2.0.5: + version "2.2.3" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.3.tgz#af89dafb23a396c7da3e862abc0be27cf51d56e1" + integrity sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.5" + es-get-iterator "^1.1.3" + get-intrinsic "^1.2.2" + is-arguments "^1.1.1" + is-array-buffer "^3.0.2" + is-date-object "^1.0.5" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + isarray "^2.0.5" + object-is "^1.1.5" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + side-channel "^1.0.4" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.13" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +dequal@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + +detect-node@^2.0.4, detect-node@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +diff-match-patch@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37" + integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw== + +diff-sequences@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" + integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-accessibility-api@^0.5.6, dom-accessibility-api@^0.5.9: + version "0.5.16" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453" + integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg== + +dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + +dompurify@^2.4.3: + version "2.5.6" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.5.6.tgz#8402b501611eaa7fb3786072297fcbe2787f8592" + integrity sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ== + +duplex-maker@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/duplex-maker/-/duplex-maker-1.0.0.tgz#1604f8b943cb0063a6d3e1fe42aa65113a79da4a" + integrity sha512-KoHuzggxg7f+vvjqOHfXxaQYI1POzBm+ah0eec7YDssZmbt6QFBI8d1nl5GQwAgR2f+VQCPvyvZtmWWqWuFtlA== + +duplexify@^3.5.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +electron-to-chromium@^1.4.820: + version "1.4.823" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.823.tgz#38587f7aa55bed14930f04091dfc65c39a3d8bd7" + integrity sha512-4h+oPeAiGQOHFyUJOqpoEcPj/xxlicxBzOErVeYVMMmAiXUXsGpsFd0QXBMaUUbnD8hhSfLf9uw+MlsoIA7j5w== + +end-of-stream@^1.0.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +env-cmd@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/env-cmd/-/env-cmd-10.1.0.tgz#c7f5d3b550c9519f137fdac4dd8fb6866a8c8c4b" + integrity sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA== + dependencies: + commander "^4.0.0" + cross-spawn "^7.0.0" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2, es-abstract@^1.23.3: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== + dependencies: + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" + has-symbols "^1.0.3" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" + is-callable "^1.2.7" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.3" + is-string "^1.0.7" + is-typed-array "^1.1.13" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.15" + +es-array-method-boxes-properly@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" + integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.2.1, es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-get-iterator@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.7" + isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" + +es-iterator-helpers@^1.0.19: + version "1.0.19" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz#117003d0e5fec237b4b5c08aded722e0c6d50ca8" + integrity sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-set-tostringtag "^2.0.3" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + globalthis "^1.0.3" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" + has-symbols "^1.0.3" + internal-slot "^1.0.7" + iterator.prototype "^1.1.2" + safe-array-concat "^1.1.2" + +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== + dependencies: + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" + +es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +esbuild@^0.21.3: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== + optionalDependencies: + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" + +escalade@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-prettier@^8.8.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz#3a06a662130807e2502fc3ff8b4143d8a0658e11" + integrity sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg== + +eslint-plugin-react-hooks@^4.6.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596" + integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== + +eslint-plugin-react-refresh@^0.4.5: + version "0.4.8" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.8.tgz#3b1db9188844101213ca637f181e84a016e36732" + integrity sha512-MIKAclwaDFIiYtVBLzDdm16E+Ty4GwhB6wZlCAG1R3Ur+F9Qbo6PRxpA5DK7XtDgm+WlCoAY2WxAwqhmIDHg6Q== + +eslint-plugin-react@^7.32.2: + version "7.34.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz#9965f27bd1250a787b5d4cfcc765e5a5d58dcb7b" + integrity sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA== + dependencies: + array-includes "^3.1.8" + array.prototype.findlast "^1.2.5" + array.prototype.flatmap "^1.3.2" + array.prototype.toreversed "^1.1.2" + array.prototype.tosorted "^1.1.4" + doctrine "^2.1.0" + es-iterator-helpers "^1.0.19" + estraverse "^5.3.0" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.8" + object.fromentries "^2.0.8" + object.hasown "^1.1.4" + object.values "^1.2.0" + prop-types "^15.8.1" + resolve "^2.0.0-next.5" + semver "^6.3.1" + string.prototype.matchall "^4.0.11" + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.56.0: + version "8.57.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" + integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.0" + "@humanwhocodes/config-array" "^0.11.14" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + 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.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eventemitter3@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +expect@^29.0.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +fault@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" + integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== + dependencies: + format "^0.2.0" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-selector@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.5.0.tgz#21c7126dc9728b31a2742d91cab20d55e67e4fb4" + integrity sha512-s8KNnmIDTBoD0p9uJ9uD0XY38SCeBOtj0UMXyQSLg1Ypfrfj8+dAvwsLjYQkQ2GjhVtp2HrnF5cJzMhBjfD8HA== + dependencies: + tslib "^2.0.3" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +filter-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" + integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ== + +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +format@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" + integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.5, function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-symbol-description@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== + dependencies: + call-bind "^1.0.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globalthis@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== + dependencies: + define-properties "^1.2.1" + gopd "^1.0.1" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +gzipper@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/gzipper/-/gzipper-7.2.0.tgz#da8c6069d66fa2a927594cc035ee144ecb853005" + integrity sha512-qwYQr7GWBXIm9Cdzud+tyM/s9N+QFzGDZoF9YR8RYJbDKOYowzjMDPEinFtm78EQeeYMC/FJW2FXY0bHkyUgsA== + dependencies: + "@gfx/zopfli" "^1.0.15" + commander "^7.2.0" + deep-equal "^2.0.5" + simple-zstd "^1.4.0" + uuid "^8.3.2" + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1, has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +has@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" + integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== + +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +hast-util-parse-selector@^2.0.0: + version "2.2.5" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" + integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ== + +hastscript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640" + integrity sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w== + dependencies: + "@types/hast" "^2.0.0" + comma-separated-tokens "^1.0.0" + hast-util-parse-selector "^2.0.0" + property-information "^5.0.0" + space-separated-tokens "^1.0.0" + +highlight.js@^10.4.1, highlight.js@~10.7.0: + version "10.7.3" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== + +history@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b" + integrity sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ== + dependencies: + "@babel/runtime" "^7.7.6" + +hoist-non-react-statics@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +hotscript@^1.0.12: + version "1.0.13" + resolved "https://registry.yarnpkg.com/hotscript/-/hotscript-1.0.13.tgz#6eb5de757e9b33444ffc22555e98dbc17fa31fb4" + integrity sha512-C++tTF1GqkGYecL+2S1wJTfoH6APGAsbb7PAWQ3iVIwgG/EFseAfEVOKFgAFq4yK3+6j1EjUD4UQ9dRJHX/sSQ== + +ignore@^5.2.0, ignore@^5.2.4: + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflection@~1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" + integrity sha512-lRy4DxuIFWXlJU7ed8UiTJOSTqStqYdEb4CEbtXfNbkdj3nH1L+reUWiE10VWcJS2yR7tge8Z74pJjtBjNwj0w== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-slot@^1.0.4, internal-slot@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.0" + side-channel "^1.0.4" + +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + +is-arguments@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-array-buffer@^3.0.2, is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-async-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + dependencies: + has-tostringtag "^1.0.0" + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.13.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.14.0.tgz#43b8ef9f46a6a08888db67b1ffd4ec9e3dfd59d1" + integrity sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A== + dependencies: + hasown "^2.0.2" + +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" + +is-date-object@^1.0.1, is-date-object@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-finalizationregistry@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" + integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== + dependencies: + call-bind "^1.0.2" + +is-generator-function@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + +is-map@^2.0.2, is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== + +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-set@^2.0.2, is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== + dependencies: + call-bind "^1.0.7" + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== + dependencies: + which-typed-array "^1.1.14" + +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-weakset@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007" + integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + +is-zst@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-zst/-/is-zst-1.0.0.tgz#97462bb1a376dabba561e249ea754801e9b90fe0" + integrity sha512-ZA5lvshKAl8z30dX7saXLpVhpsq3d2EHK9uf7qtUjnOtdw4XBpAoWb2RvZ5kyoaebdoidnGI0g2hn9Z7ObPbww== + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +iterator.prototype@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" + integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w== + dependencies: + define-properties "^1.2.1" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + reflect.getprototypeof "^1.0.4" + set-function-name "^2.0.1" + +jest-diff@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" + integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-get-type@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" + integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-matcher-utils@^27.0.0: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" + integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== + dependencies: + chalk "^4.0.0" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-compare@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/json-schema-compare/-/json-schema-compare-0.2.2.tgz#dd601508335a90c7f4cfadb6b2e397225c908e56" + integrity sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ== + dependencies: + lodash "^4.17.4" + +json-schema-merge-allof@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz#ed2828cdd958616ff74f932830a26291789eaaf2" + integrity sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w== + dependencies: + compute-lcm "^1.1.2" + json-schema-compare "^0.2.2" + lodash "^4.17.20" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonexport@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsonexport/-/jsonexport-3.2.0.tgz#e5b4905ea1f6c8f8e0f62e4ceb26e4a31f1c93a8" + integrity sha512-GbO9ugb0YTZatPd/hqCGR0FSwbr82H6OzG04yzdrG7XOe4QZ0jhQ+kOsB29zqkzoYJLmLxbbrFiuwbQu891XnQ== + +jsonpointer@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559" + integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ== + +"jsx-ast-utils@^2.4.1 || ^3.0.0": + version "3.3.5" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" + integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== + dependencies: + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + object.assign "^4.1.4" + object.values "^1.1.6" + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +linkify-it@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421" + integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ== + dependencies: + uc.micro "^2.0.0" + +linkifyjs@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-4.1.3.tgz#0edbc346428a7390a23ea2e5939f76112c9ae07f" + integrity sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg== + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@~4.17.5: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lowlight@^1.17.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.20.0.tgz#ddb197d33462ad0d93bf19d17b6c301aa3941888" + integrity sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw== + dependencies: + fault "^1.0.0" + highlight.js "~10.7.0" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lz-string@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" + integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== + +markdown-it@^14.0.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45" + integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg== + dependencies: + argparse "^2.0.1" + entities "^4.4.0" + linkify-it "^5.0.0" + mdurl "^2.0.0" + punycode.js "^2.3.1" + uc.micro "^2.1.0" + +markdown-to-jsx@^7.4.1: + version "7.4.7" + resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.4.7.tgz#740ee7ec933865ef5cc683a0992797685a75e2ee" + integrity sha512-0+ls1IQZdU6cwM1yu0ZjjiVWYtkbExSyUIFU2ZeDIFuZM1W42Mh4OlJ4nb4apX4H8smxDHRdFaoIVJGwfv5hkg== + +match-sorter@^6.0.2: + version "6.3.4" + resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.4.tgz#afa779d8e922c81971fbcb4781c7003ace781be7" + integrity sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg== + dependencies: + "@babel/runtime" "^7.23.8" + remove-accents "0.5.0" + +mdurl@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0" + integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.7" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" + integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +microseconds@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39" + integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA== + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nano-time@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef" + integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA== + dependencies: + big-integer "^1.6.16" + +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +node-polyglot@^2.2.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/node-polyglot/-/node-polyglot-2.5.0.tgz#bd2703f5c5e784c3917abeaa4b5d4604a4722d7e" + integrity sha512-zXVwHNhFsG3mls+LKHxoHF70GQOL3FTDT3jH7ldkb95kG76RdU7F/NbvxV7D2hNIL9VpWXW6y78Fz+3KZkatRg== + dependencies: + array.prototype.foreach "^1.0.2" + has "^1.0.3" + object.entries "^1.1.5" + string.prototype.trim "^1.2.6" + warning "^4.0.3" + +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + +object-is@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07" + integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4, object.assign@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== + dependencies: + call-bind "^1.0.5" + define-properties "^1.2.1" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.entries@^1.1.5, object.entries@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" + integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +object.hasown@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.4.tgz#e270ae377e4c120cdcb7656ce66884a6218283dc" + integrity sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg== + dependencies: + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +object.values@^1.1.6, object.values@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +oblivious-set@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566" + integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw== + +once@^1.3.0, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +orderedmap@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/orderedmap/-/orderedmap-2.1.1.tgz#61481269c44031c449915497bf5a4ad273c512d2" + integrity sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g== + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" + integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +peek-stream@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/peek-stream/-/peek-stream-1.1.3.tgz#3b35d84b7ccbbd262fff31dc10da56856ead6d67" + integrity sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA== + dependencies: + buffer-from "^1.0.0" + duplexify "^3.5.0" + through2 "^2.0.3" + +picocolors@^1.0.0, picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + +picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + +postcss@^8.4.39: + version "8.4.39" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.39.tgz#aa3c94998b61d3a9c259efa51db4b392e1bde0e3" + integrity sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.1" + source-map-js "^1.2.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier@^2.8.8: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== + +pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prismjs@^1.27.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12" + integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q== + +prismjs@~1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057" + integrity sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process-streams@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/process-streams/-/process-streams-1.0.3.tgz#8df3e807932fc80cbb2ab92dd7c6f199c5faa9b1" + integrity sha512-xkIaM5vYnyekB88WyET78YEqXiaJRy0xcvIdE22n+myhvBT7LlLmX6iAtq7jDvVH8CUx2rqQsd32JdRyJMV3NA== + dependencies: + duplex-maker "^1.0.0" + +prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.0, prop-types@^15.7.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +property-information@^5.0.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" + integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== + dependencies: + xtend "^4.0.0" + +prosemirror-changeset@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz#dae94b63aec618fac7bb9061648e6e2a79988383" + integrity sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ== + dependencies: + prosemirror-transform "^1.0.0" + +prosemirror-collab@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz#0e8c91e76e009b53457eb3b3051fb68dad029a33" + integrity sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ== + dependencies: + prosemirror-state "^1.0.0" + +prosemirror-commands@^1.0.0, prosemirror-commands@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz#e94aeea52286f658cd984270de9b4c3fff580852" + integrity sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.0.0" + +prosemirror-dropcursor@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz#49b9fb2f583e0d0f4021ff87db825faa2be2832d" + integrity sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw== + dependencies: + prosemirror-state "^1.0.0" + prosemirror-transform "^1.1.0" + prosemirror-view "^1.1.0" + +prosemirror-gapcursor@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.3.2.tgz#5fa336b83789c6199a7341c9493587e249215cb4" + integrity sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ== + dependencies: + prosemirror-keymap "^1.0.0" + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-view "^1.0.0" + +prosemirror-history@^1.0.0, prosemirror-history@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/prosemirror-history/-/prosemirror-history-1.4.1.tgz#cc370a46fb629e83a33946a0e12612e934ab8b98" + integrity sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ== + dependencies: + prosemirror-state "^1.2.2" + prosemirror-transform "^1.0.0" + prosemirror-view "^1.31.0" + rope-sequence "^1.3.0" + +prosemirror-inputrules@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz#ef1519bb2cb0d1e0cec74bad1a97f1c1555068bb" + integrity sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg== + dependencies: + prosemirror-state "^1.0.0" + prosemirror-transform "^1.0.0" + +prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.2, prosemirror-keymap@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.2.2.tgz#14a54763a29c7b2704f561088ccf3384d14eb77e" + integrity sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ== + dependencies: + prosemirror-state "^1.0.0" + w3c-keyname "^2.2.0" + +prosemirror-markdown@^1.12.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/prosemirror-markdown/-/prosemirror-markdown-1.13.0.tgz#67ebfa40af48a22d1e4ed6cad2e29851eb61e649" + integrity sha512-UziddX3ZYSYibgx8042hfGKmukq5Aljp2qoBiJRejD/8MH70siQNz5RB1TrdTPheqLMy4aCe4GYNF10/3lQS5g== + dependencies: + markdown-it "^14.0.0" + prosemirror-model "^1.20.0" + +prosemirror-menu@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz#3cfdc7c06d10f9fbd1bce29082c498bd11a0a79a" + integrity sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA== + dependencies: + crelt "^1.0.0" + prosemirror-commands "^1.0.0" + prosemirror-history "^1.0.0" + prosemirror-state "^1.0.0" + +prosemirror-model@^1.0.0, prosemirror-model@^1.19.0, prosemirror-model@^1.19.4, prosemirror-model@^1.20.0, prosemirror-model@^1.21.0, prosemirror-model@^1.8.1: + version "1.21.3" + resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.21.3.tgz#97fa434d670331c1ab25f75964b1bcd7a948ce61" + integrity sha512-nt2Xs/RNGepD9hrrkzXvtCm1mpGJoQfFSPktGa0BF/aav6XsnmVGZ9sTXNWRLupAz5SCLa3EyKlFeK7zJWROKg== + dependencies: + orderedmap "^2.0.0" + +prosemirror-schema-basic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.2.tgz#6695f5175e4628aab179bf62e5568628b9cfe6c7" + integrity sha512-/dT4JFEGyO7QnNTe9UaKUhjDXbTNkiWTq/N4VpKaF79bBjSExVV2NXmJpcM7z/gD7mbqNjxbmWW5nf1iNSSGnw== + dependencies: + prosemirror-model "^1.19.0" + +prosemirror-schema-list@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.4.0.tgz#03f210a25ec0e36b717defb486d2081d733a40dc" + integrity sha512-nZOIq/AkBSzCENxUyLm5ltWE53e2PLk65ghMN8qLQptOmDVixZlPqtMeQdiNw0odL9vNpalEjl3upgRkuJ/Jyw== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.7.3" + +prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.1, prosemirror-state@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.4.3.tgz#94aecf3ffd54ec37e87aa7179d13508da181a080" + integrity sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-transform "^1.0.0" + prosemirror-view "^1.27.0" + +prosemirror-tables@^1.3.5: + version "1.3.7" + resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-1.3.7.tgz#9d296bd432d2bc7dca90f14e5c3b5c5f61277f7a" + integrity sha512-oEwX1wrziuxMtwFvdDWSFHVUWrFJWt929kVVfHvtTi8yvw+5ppxjXZkMG/fuTdFo+3DXyIPSKfid+Be1npKXDA== + dependencies: + prosemirror-keymap "^1.1.2" + prosemirror-model "^1.8.1" + prosemirror-state "^1.3.1" + prosemirror-transform "^1.2.1" + prosemirror-view "^1.13.3" + +prosemirror-trailing-node@^2.0.7: + version "2.0.8" + resolved "https://registry.yarnpkg.com/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.8.tgz#233ddcbda72de06f9b5d758d2a65a8cac482ea10" + integrity sha512-ujRYhSuhQb1Jsarh1IHqb2KoSnRiD7wAMDGucP35DN7j5af6X7B18PfdPIrbwsPTqIAj0fyOvxbuPsWhNvylmA== + dependencies: + "@remirror/core-constants" "^2.0.2" + escape-string-regexp "^4.0.0" + +prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.2.1, prosemirror-transform@^1.7.3, prosemirror-transform@^1.8.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.9.0.tgz#81fd1fbd887929a95369e6dd3d240c23c19313f8" + integrity sha512-5UXkr1LIRx3jmpXXNKDhv8OyAOeLTGuXNwdVfg8x27uASna/wQkr9p6fD3eupGOi4PLJfbezxTyi/7fSJypXHg== + dependencies: + prosemirror-model "^1.21.0" + +prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.32.7: + version "1.33.8" + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.33.8.tgz#cfd76dff421730cbca0b6ea40ce36994daaeda41" + integrity sha512-4PhMr/ufz2cdvFgpUAnZfs+0xij3RsFysreeG9V/utpwX7AJtYCDVyuRxzWoMJIEf4C7wVihuBNMPpFLPCiLQw== + dependencies: + prosemirror-model "^1.20.0" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.1.0" + +punycode.js@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7" + integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +query-string@^7.1.1: + version "7.1.3" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328" + integrity sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg== + dependencies: + decode-uri-component "^0.2.2" + filter-obj "^1.1.0" + split-on-first "^1.0.0" + strict-uri-encode "^2.0.0" + +querystring@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" + integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +ra-core@^4.11.0, ra-core@^4.16.19: + version "4.16.19" + resolved "https://registry.yarnpkg.com/ra-core/-/ra-core-4.16.19.tgz#d402cde87368ddfbd30a540b7e9f8e1c6ff0fec6" + integrity sha512-1qNuLGaGSHYv5esqJcu7n/PeMKTBXA3JXzjQPAPDK9dBsuWC1IXx9MilivANwh8doYbpFfqsX8VJyW1aqIG1Pg== + dependencies: + clsx "^1.1.1" + date-fns "^2.19.0" + eventemitter3 "^4.0.7" + inflection "~1.12.0" + jsonexport "^3.2.0" + lodash "~4.17.5" + prop-types "^15.6.1" + query-string "^7.1.1" + react-is "^17.0.2" + react-query "^3.32.1" + +ra-data-json-server@^4.7.2: + version "4.16.19" + resolved "https://registry.yarnpkg.com/ra-data-json-server/-/ra-data-json-server-4.16.19.tgz#1c3715a8168b71782c3a6841df073ab5cd2a80b3" + integrity sha512-xhaQoaPIcx95WTDrn40DRaQoe7mFAyWC6dKWos7R96kxD/4U/+chp1Stj6JmX8XW70brerWyKJwNmRrSZWg9eQ== + dependencies: + query-string "^7.1.1" + ra-core "^4.16.19" + +ra-i18n-polyglot@^4.11.0: + version "4.16.19" + resolved "https://registry.yarnpkg.com/ra-i18n-polyglot/-/ra-i18n-polyglot-4.16.19.tgz#884100ea7f20ddf044e72c5d78c1c5c19fc0dd12" + integrity sha512-gRnY0fUn61cVtR36Qf5mgULXnQALRrjZ8Hnp7w+U9YvtrzapNTuIyZem3Tp0QL+/jRgxeqlQW7dqPYdV0bC7vg== + dependencies: + node-polyglot "^2.2.2" + ra-core "^4.16.19" + +ra-input-rich-text@^4.14.4: + version "4.16.19" + resolved "https://registry.yarnpkg.com/ra-input-rich-text/-/ra-input-rich-text-4.16.19.tgz#01c0a7f5e61213ad07735445a526362b5a19393d" + integrity sha512-cE71yaw8Q0S0Q8LJItbxyXaPoILWhd0wg+ciss7XwcgU95mUwxwhIKoRwlM+zWAZ+s3Q1eGnZF7uRRyPIstEFw== + dependencies: + "@tiptap/core" "^2.0.3" + "@tiptap/extension-color" "^2.0.3" + "@tiptap/extension-highlight" "^2.0.3" + "@tiptap/extension-image" "^2.0.3" + "@tiptap/extension-link" "^2.0.3" + "@tiptap/extension-placeholder" "^2.0.3" + "@tiptap/extension-text-align" "^2.0.3" + "@tiptap/extension-text-style" "^2.0.3" + "@tiptap/extension-underline" "^2.0.3" + "@tiptap/pm" "^2.0.3" + "@tiptap/react" "^2.0.3" + "@tiptap/starter-kit" "^2.0.3" + clsx "^1.1.1" + +ra-language-english@^4.11.0: + version "4.16.19" + resolved "https://registry.yarnpkg.com/ra-language-english/-/ra-language-english-4.16.19.tgz#5e99bbfbab0b99a1ed31d9df9e01e51e08c78a85" + integrity sha512-k8ykj7bJ5UEAebB+SsOAcpyb6gUlsNkJ8N0+lDAezpilBaHahDQaYtNKA+GkoZnU8rIKYMYLttcl3VdCllkG2g== + dependencies: + ra-core "^4.16.19" + +ra-ui-materialui@^4.11.0: + version "4.16.19" + resolved "https://registry.yarnpkg.com/ra-ui-materialui/-/ra-ui-materialui-4.16.19.tgz#67a7a03a8786e8db3ad6aeebb34535984df6e9c8" + integrity sha512-EyalFIUq9oUQ8N/vAeQFlrBaRTU/pMPAHvmfPHUxL5ajcQaSii6XKhRgT9S+YOec/XAU0DDaTjH9oJm0H3UgNA== + dependencies: + autosuggest-highlight "^3.1.1" + clsx "^1.1.1" + css-mediaquery "^0.1.2" + dompurify "^2.4.3" + hotscript "^1.0.12" + inflection "~1.12.0" + jsonexport "^3.2.0" + lodash "~4.17.5" + prop-types "^15.7.0" + query-string "^7.1.1" + react-dropzone "^12.0.4" + react-error-boundary "^3.1.4" + react-query "^3.32.1" + react-transition-group "^4.4.1" + +react-ace@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-10.1.0.tgz#d348eac2b16475231779070b6cd16768deed565f" + integrity sha512-VkvUjZNhdYTuKOKQpMIZi7uzZZVgzCjM7cLYu6F64V0mejY8a2XTyPUIMszC6A4trbeMIHbK5fYFcT/wkP/8VA== + dependencies: + ace-builds "^1.4.14" + diff-match-patch "^1.0.5" + lodash.get "^4.4.2" + lodash.isequal "^4.5.0" + prop-types "^15.7.2" + +react-admin@4.11.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/react-admin/-/react-admin-4.11.0.tgz#9e9ca3b6407f7d9b0675d62cfa3e6790ae5f80b6" + integrity sha512-iYmFX5klpiyKvP0r33vXX0XR5K1lFtwZ2XivBVIvCnjA01haBWPxkS61VH2oAeYKTVYBVk+0oqvwKzOp03ANSA== + dependencies: + "@emotion/react" "^11.4.1" + "@emotion/styled" "^11.3.0" + "@mui/icons-material" "^5.0.1" + "@mui/material" "^5.0.2" + history "^5.1.0" + ra-core "^4.11.0" + ra-i18n-polyglot "^4.11.0" + ra-language-english "^4.11.0" + ra-ui-materialui "^4.11.0" + react-hook-form "^7.43.9" + react-router "^6.1.0" + react-router-dom "^6.1.0" + +react-dom@^18.2.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.2" + +react-dropzone@^12.0.4: + version "12.1.0" + resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-12.1.0.tgz#e097b37e9da6f9e324efc757b7434ebc6f3dc2cb" + integrity sha512-iBYHA1rbopIvtzokEX4QubO6qk5IF/x3BtKGu74rF2JkQDXnwC4uO/lHKpaw4PJIV6iIAYOlwLv2FpiGyqHNog== + dependencies: + attr-accept "^2.2.2" + file-selector "^0.5.0" + prop-types "^15.8.1" + +react-error-boundary@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz#255db92b23197108757a888b01e5b729919abde0" + integrity sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA== + dependencies: + "@babel/runtime" "^7.12.5" + +react-hook-form@^7.43.9: + version "7.52.1" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.52.1.tgz#ec2c96437b977f8b89ae2d541a70736c66284852" + integrity sha512-uNKIhaoICJ5KQALYZ4TOaOLElyM+xipord+Ha3crEFhTntdLvWZqVY49Wqd/0GiVCA/f9NjemLeiNPjG7Hpurg== + +react-is@^16.13.1, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^17.0.1, react-is@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-is@^18.0.0, react-is@^18.2.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + +react-query@^3.32.1: + version "3.39.3" + resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.3.tgz#4cea7127c6c26bdea2de5fb63e51044330b03f35" + integrity sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g== + dependencies: + "@babel/runtime" "^7.5.5" + broadcast-channel "^3.4.1" + match-sorter "^6.0.2" + +react-refresh@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" + integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== + +react-router-dom@^6.1.0, react-router-dom@^6.18.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.24.1.tgz#b1a22f7d6c5a1bfce30732bd370713f991ab4de4" + integrity sha512-U19KtXqooqw967Vw0Qcn5cOvrX5Ejo9ORmOtJMzYWtCT4/WOfFLIZGGsVLxcd9UkBO0mSTZtXqhZBsWlHr7+Sg== + dependencies: + "@remix-run/router" "1.17.1" + react-router "6.24.1" + +react-router@6.24.1, react-router@^6.1.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.24.1.tgz#5a3bbba0000afba68d42915456ca4c806f37a7de" + integrity sha512-PTXFXGK2pyXpHzVo3rR9H7ip4lSPZZc0bHG5CARmj65fTT6qG7sTngmb6lcYu1gf3y/8KxORoy9yn59pGpCnpg== + dependencies: + "@remix-run/router" "1.17.1" + +react-syntax-highlighter@^15.5.0: + version "15.5.0" + resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz#4b3eccc2325fa2ec8eff1e2d6c18fa4a9e07ab20" + integrity sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg== + dependencies: + "@babel/runtime" "^7.3.1" + highlight.js "^10.4.1" + lowlight "^1.17.0" + prismjs "^1.27.0" + refractor "^3.6.0" + +react-transition-group@^4.4.1, react-transition-group@^4.4.5: + version "4.4.5" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" + integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + +react@^18.2.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" + integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== + dependencies: + loose-envify "^1.1.0" + +readable-stream@3: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^2.0.0, readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + +reflect.getprototypeof@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" + integrity sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.1" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + globalthis "^1.0.3" + which-builtin-type "^1.1.3" + +refractor@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.6.0.tgz#ac318f5a0715ead790fcfb0c71f4dd83d977935a" + integrity sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA== + dependencies: + hastscript "^6.0.0" + parse-entities "^2.0.0" + prismjs "~1.27.0" + +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== + dependencies: + call-bind "^1.0.6" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.1" + +remove-accents@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.5.0.tgz#77991f37ba212afba162e375b627631315bed687" + integrity sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A== + +remove-accents@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.4.tgz#73704abf7dae3764295d475d2b6afac4ea23e4d9" + integrity sha512-EpFcOa/ISetVHEXqu+VwI96KZBmq+a8LJnGkaeFw45epGlxIZz5dhEEnNZMsQXgORu3qaMoLX4qJCzOik6ytAg== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.19.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^2.0.0-next.5: + version "2.0.0-next.5" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@3.0.2, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rollup@^4.13.0: + version "4.18.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.18.1.tgz#18a606df5e76ca53b8a69f2d8eab256d69dda851" + integrity sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A== + dependencies: + "@types/estree" "1.0.5" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.18.1" + "@rollup/rollup-android-arm64" "4.18.1" + "@rollup/rollup-darwin-arm64" "4.18.1" + "@rollup/rollup-darwin-x64" "4.18.1" + "@rollup/rollup-linux-arm-gnueabihf" "4.18.1" + "@rollup/rollup-linux-arm-musleabihf" "4.18.1" + "@rollup/rollup-linux-arm64-gnu" "4.18.1" + "@rollup/rollup-linux-arm64-musl" "4.18.1" + "@rollup/rollup-linux-powerpc64le-gnu" "4.18.1" + "@rollup/rollup-linux-riscv64-gnu" "4.18.1" + "@rollup/rollup-linux-s390x-gnu" "4.18.1" + "@rollup/rollup-linux-x64-gnu" "4.18.1" + "@rollup/rollup-linux-x64-musl" "4.18.1" + "@rollup/rollup-win32-arm64-msvc" "4.18.1" + "@rollup/rollup-win32-ia32-msvc" "4.18.1" + "@rollup/rollup-win32-x64-msvc" "4.18.1" + fsevents "~2.3.2" + +rope-sequence@^1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.4.tgz#df85711aaecd32f1e756f76e43a415171235d425" + integrity sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + has-symbols "^1.0.3" + isarray "^2.0.5" + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex-test@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" + integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-regex "^1.1.4" + +scheduler@^0.23.2: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== + dependencies: + loose-envify "^1.1.0" + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.4: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.1, set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4, side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +simple-zstd@^1.4.0: + version "1.4.2" + resolved "https://registry.yarnpkg.com/simple-zstd/-/simple-zstd-1.4.2.tgz#4f5b7b05dfd2930b03092eb0c0cd13a44bad4b34" + integrity sha512-kGYEvT33M5XfyQvvW4wxl3eKcWbdbCc1V7OZzuElnaXft0qbVzoIIXHXiCm3JCUki+MZKKmvjl8p2VGLJc5Y/A== + dependencies: + is-zst "^1.0.0" + peek-stream "^1.1.3" + process-streams "^1.0.1" + through2 "^4.0.2" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-js@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" + integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== + +source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +space-separated-tokens@^1.0.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" + integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== + +split-on-first@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" + integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== + dependencies: + internal-slot "^1.0.4" + +stream-shift@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.3.tgz#85b8fab4d71010fc3ba8772e8046cc49b8a3864b" + integrity sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ== + +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== + +string.prototype.matchall@^4.0.11: + version "4.0.11" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a" + integrity sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.7" + regexp.prototype.flags "^1.5.2" + set-function-name "^2.0.2" + side-channel "^1.0.6" + +string.prototype.trim@^1.2.6, string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" + +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +stylis@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" + integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +through2@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through2@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" + integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== + dependencies: + readable-stream "3" + +tippy.js@^6.3.7: + version "6.3.7" + resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c" + integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ== + dependencies: + "@popperjs/core" "^2.9.0" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-api-utils@^1.0.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + +tslib@^2.0.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-typed-array "^1.1.13" + +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + +typeface-roboto-mono@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/typeface-roboto-mono/-/typeface-roboto-mono-1.1.13.tgz#2af8662db8f9119c00efd55d6ed8877d2a69ec94" + integrity sha512-pnzDc70b7ywJHin/BUFL7HZX8DyOTBLT2qxlJ92eH1UJOFcENIBXa9IZrxsJX/gEKjbEDKhW5vz/TKRBNk/ufQ== + +typeface-titillium-web@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/typeface-titillium-web/-/typeface-titillium-web-1.1.13.tgz#3fb50c8c7ea0cbc3531cad7f1a23d7218aeb24be" + integrity sha512-R21mXf9hoqle+dgR7k6C6QUN2XElopQNsTDYI5DoU1buuYayVvzn2jd2ihKJTwM/hJsltLrlJUkyumc3FFgevA== + +typescript@^5.2.2: + version "5.5.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.3.tgz#e1b0a3c394190838a0b168e771b0ad56a0af0faa" + integrity sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ== + +uc.micro@^2.0.0, uc.micro@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" + integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +unload@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7" + integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA== + dependencies: + "@babel/runtime" "^7.6.2" + detect-node "^2.0.4" + +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== + dependencies: + escalade "^3.1.2" + picocolors "^1.0.1" + +uri-js@^4.2.2, uri-js@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +validate.io-array@^1.0.3: + version "1.0.6" + resolved "https://registry.yarnpkg.com/validate.io-array/-/validate.io-array-1.0.6.tgz#5b5a2cafd8f8b85abb2f886ba153f2d93a27774d" + integrity sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg== + +validate.io-function@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/validate.io-function/-/validate.io-function-1.0.2.tgz#343a19802ed3b1968269c780e558e93411c0bad7" + integrity sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ== + +validate.io-integer-array@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz#2cabde033293a6bcbe063feafe91eaf46b13a089" + integrity sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA== + dependencies: + validate.io-array "^1.0.3" + validate.io-integer "^1.0.4" + +validate.io-integer@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/validate.io-integer/-/validate.io-integer-1.0.5.tgz#168496480b95be2247ec443f2233de4f89878068" + integrity sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ== + dependencies: + validate.io-number "^1.0.3" + +validate.io-number@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/validate.io-number/-/validate.io-number-1.0.3.tgz#f63ffeda248bf28a67a8d48e0e3b461a1665baf8" + integrity sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg== + +vite@^5.1.4: + version "5.3.3" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.3.3.tgz#5265b1f0a825b3b6564c2d07524777c83e3c04c2" + integrity sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A== + dependencies: + esbuild "^0.21.3" + postcss "^8.4.39" + rollup "^4.13.0" + optionalDependencies: + fsevents "~2.3.3" + +w3c-keyname@^2.2.0: + version "2.2.8" + resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5" + integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ== + +warning@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-builtin-type@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" + integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== + dependencies: + function.prototype.name "^1.1.5" + has-tostringtag "^1.0.0" + is-async-function "^2.0.0" + is-date-object "^1.0.5" + is-finalizationregistry "^1.0.2" + is-generator-function "^1.0.10" + is-regex "^1.1.4" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.9" + +which-collection@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + +which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.9: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.2" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yaml@^1.10.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yaml@^2.3.4: + version "2.4.5" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.5.tgz#60630b206dd6d84df97003d33fc1ddf6296cca5e" + integrity sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/package.json b/package.json new file mode 100644 index 000000000..5802acb45 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "AAC", + "version": "5.x", + "private": true, + "scripts": { + "prettier": "prettier --config ./.prettierrc.yml --write --list-different \"src/**/*.java\"", + "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1 --skip-unstable" + }, + "devDependencies": { + "conventional-changelog-cli": "^5.0.0", + "prettier": "^3.2.5", + "prettier-plugin-java": "^2.5.0" + }, + "dependencies": {}, + "eslintConfig": {} + } + \ No newline at end of file diff --git a/pom.xml b/pom.xml index c45fab3d0..0a4336d43 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 it.smartcommunitylab aac - 5.0.3-SNAPSHOT + ${revision} aac @@ -14,14 +14,15 @@ + 5.2.0-SNAPSHOT 17 1.74 1.6.15 1.17.2 2.0.0 4.33.1 - v16.15.0 - v1.21.1 + v18.17.1 + v1.22.19 42.7.1 8.3.0 3.3.2 @@ -131,11 +132,6 @@ spring-session-jdbc - - org.springframework.security.oauth - spring-security-oauth2 - 2.6.0.SNAPSHOT - org.apache.commons @@ -470,7 +466,7 @@ generate-resources - install + install --frozen-lockfile ${project.basedir}/user-console @@ -487,6 +483,54 @@ + + dev-console-yarn-install + + yarn + + generate-resources + + install --frozen-lockfile + ${project.basedir}/dev-console + + + + + dev console build + + yarn + + compile + + build + ${project.basedir}/dev-console + + + + + admin-console-yarn-install + + yarn + + generate-resources + + install --frozen-lockfile + ${project.basedir}/admin-console + + + + + admin console build + + yarn + + compile + + dist + ${project.basedir}/admin-console + + + @@ -508,6 +552,38 @@ + + dev console package + + copy-resources + + process-classes + + ${project.build.outputDirectory}/console/dev + + + ${project.basedir}/dev-console/dist + false + + + + + + admin console package + + copy-resources + + process-classes + + ${project.build.outputDirectory}/console/admin + + + ${project.basedir}/admin-console/build + false + + + + @@ -560,10 +636,10 @@ - + Shibboleth https://build.shibboleth.net/maven/releases diff --git a/src/main/java/it/smartcommunitylab/aac/SystemKeys.java b/src/main/java/it/smartcommunitylab/aac/SystemKeys.java index 777c8f5fd..cdc7fcff1 100644 --- a/src/main/java/it/smartcommunitylab/aac/SystemKeys.java +++ b/src/main/java/it/smartcommunitylab/aac/SystemKeys.java @@ -24,7 +24,7 @@ public class SystemKeys { // TODO implement public static final long AAC_COMMON_SERIAL_VERSION = 420L; public static final long AAC_CORE_SERIAL_VERSION = 420L; - public static final long AAC_OAUTH2_SERIAL_VERSION = 420L; + public static final long AAC_OAUTH2_SERIAL_VERSION = 520L; public static final long AAC_OIDC_SERIAL_VERSION = 420L; public static final long AAC_SAML_SERIAL_VERSION = 420L; public static final long AAC_APPLE_SERIAL_VERSION = 420L; @@ -121,7 +121,7 @@ public class SystemKeys { public static final String SLUG_PATTERN = "^[a-zA-Z0-9._-]+$"; public static final String ID_PATTERN = "^[a-zA-Z0-9_-|]+$"; public static final String EMAIL_PATTERN = "^[a-zA-Z0-9._@-]+$"; - public static final String SCOPE_PATTERN = "^[a-zA-Z.:]{3,}$"; + public static final String SCOPE_PATTERN = "^[a-zA-Z.:_-]{3,}$"; public static final String RESOURCE_PATTERN = "^[a-zA-Z0-9._:/-]+$"; public static final String NAMESPACE_PATTERN = "^[a-zA-Z0-9._:/-]+$"; public static final String KEY_PATTERN = "^[a-zA-Z0-9._]+$"; diff --git a/src/main/java/it/smartcommunitylab/aac/attributes/AccountAttributesSet.java b/src/main/java/it/smartcommunitylab/aac/attributes/AccountAttributesSet.java index 840f8f605..72b9a63c7 100644 --- a/src/main/java/it/smartcommunitylab/aac/attributes/AccountAttributesSet.java +++ b/src/main/java/it/smartcommunitylab/aac/attributes/AccountAttributesSet.java @@ -16,8 +16,8 @@ package it.smartcommunitylab.aac.attributes; +import it.smartcommunitylab.aac.attributes.base.BaseAttributeSet; import it.smartcommunitylab.aac.attributes.model.Attribute; -import it.smartcommunitylab.aac.attributes.model.AttributeSet; import it.smartcommunitylab.aac.attributes.model.StringAttribute; import java.util.ArrayList; import java.util.Collection; @@ -28,7 +28,7 @@ import org.springframework.stereotype.Component; @Component -public class AccountAttributesSet implements AttributeSet { +public class AccountAttributesSet extends BaseAttributeSet { public static final String IDENTIFIER = "aac.account"; private static final List keys; diff --git a/src/main/java/it/smartcommunitylab/aac/attributes/BasicAttributesSet.java b/src/main/java/it/smartcommunitylab/aac/attributes/BasicAttributesSet.java index 9110c8a95..758465829 100644 --- a/src/main/java/it/smartcommunitylab/aac/attributes/BasicAttributesSet.java +++ b/src/main/java/it/smartcommunitylab/aac/attributes/BasicAttributesSet.java @@ -16,8 +16,8 @@ package it.smartcommunitylab.aac.attributes; +import it.smartcommunitylab.aac.attributes.base.BaseAttributeSet; import it.smartcommunitylab.aac.attributes.model.Attribute; -import it.smartcommunitylab.aac.attributes.model.AttributeSet; import it.smartcommunitylab.aac.attributes.model.StringAttribute; import java.util.ArrayList; import java.util.Collection; @@ -28,7 +28,7 @@ import org.springframework.stereotype.Component; @Component -public class BasicAttributesSet implements AttributeSet { +public class BasicAttributesSet extends BaseAttributeSet { public static final String IDENTIFIER = "aac.basic"; private static final List keys; diff --git a/src/main/java/it/smartcommunitylab/aac/attributes/DefaultAttributesSet.java b/src/main/java/it/smartcommunitylab/aac/attributes/DefaultAttributesSet.java index ac3684c72..3a7bc3163 100644 --- a/src/main/java/it/smartcommunitylab/aac/attributes/DefaultAttributesSet.java +++ b/src/main/java/it/smartcommunitylab/aac/attributes/DefaultAttributesSet.java @@ -95,6 +95,10 @@ public Collection getAttributes() { public void setAttributes(Collection attributes) { this.attributes = attributes; } + + public String getId() { + return this.identifier; + } public void addAttributes(Collection attributes) { this.attributes = new HashSet<>(); diff --git a/src/main/java/it/smartcommunitylab/aac/attributes/EmailAttributesSet.java b/src/main/java/it/smartcommunitylab/aac/attributes/EmailAttributesSet.java index 79df4fbd1..fbc4d4adc 100644 --- a/src/main/java/it/smartcommunitylab/aac/attributes/EmailAttributesSet.java +++ b/src/main/java/it/smartcommunitylab/aac/attributes/EmailAttributesSet.java @@ -16,8 +16,8 @@ package it.smartcommunitylab.aac.attributes; +import it.smartcommunitylab.aac.attributes.base.BaseAttributeSet; import it.smartcommunitylab.aac.attributes.model.Attribute; -import it.smartcommunitylab.aac.attributes.model.AttributeSet; import it.smartcommunitylab.aac.attributes.model.BooleanAttribute; import it.smartcommunitylab.aac.attributes.model.StringAttribute; import java.util.ArrayList; @@ -29,7 +29,7 @@ import org.springframework.stereotype.Component; @Component -public class EmailAttributesSet implements AttributeSet { +public class EmailAttributesSet extends BaseAttributeSet { public static final String IDENTIFIER = "aac.email"; private static final List keys; diff --git a/src/main/java/it/smartcommunitylab/aac/attributes/OpenIdAttributesSet.java b/src/main/java/it/smartcommunitylab/aac/attributes/OpenIdAttributesSet.java index 5a6e8a0f3..bec3aba45 100644 --- a/src/main/java/it/smartcommunitylab/aac/attributes/OpenIdAttributesSet.java +++ b/src/main/java/it/smartcommunitylab/aac/attributes/OpenIdAttributesSet.java @@ -16,8 +16,8 @@ package it.smartcommunitylab.aac.attributes; +import it.smartcommunitylab.aac.attributes.base.BaseAttributeSet; import it.smartcommunitylab.aac.attributes.model.Attribute; -import it.smartcommunitylab.aac.attributes.model.AttributeSet; import it.smartcommunitylab.aac.attributes.model.BooleanAttribute; import it.smartcommunitylab.aac.attributes.model.DateAttribute; import it.smartcommunitylab.aac.attributes.model.StringAttribute; @@ -31,7 +31,7 @@ import org.springframework.stereotype.Component; @Component -public class OpenIdAttributesSet implements AttributeSet { +public class OpenIdAttributesSet extends BaseAttributeSet { public static final String IDENTIFIER = "aac.openid"; private static final List keys; diff --git a/src/main/java/it/smartcommunitylab/aac/attributes/SamlAttributesSet.java b/src/main/java/it/smartcommunitylab/aac/attributes/SamlAttributesSet.java index 382e9162f..662ca6a3f 100644 --- a/src/main/java/it/smartcommunitylab/aac/attributes/SamlAttributesSet.java +++ b/src/main/java/it/smartcommunitylab/aac/attributes/SamlAttributesSet.java @@ -16,8 +16,8 @@ package it.smartcommunitylab.aac.attributes; +import it.smartcommunitylab.aac.attributes.base.BaseAttributeSet; import it.smartcommunitylab.aac.attributes.model.Attribute; -import it.smartcommunitylab.aac.attributes.model.AttributeSet; import it.smartcommunitylab.aac.attributes.model.BooleanAttribute; import it.smartcommunitylab.aac.attributes.model.StringAttribute; import java.util.ArrayList; @@ -29,7 +29,7 @@ import org.springframework.stereotype.Component; @Component -public class SamlAttributesSet implements AttributeSet { +public class SamlAttributesSet extends BaseAttributeSet { public static final String IDENTIFIER = "aac.saml"; private static final List keys; diff --git a/src/main/java/it/smartcommunitylab/aac/attributes/base/AbstractAttributes.java b/src/main/java/it/smartcommunitylab/aac/attributes/base/AbstractAttributes.java index 89565ea98..68ad1e470 100644 --- a/src/main/java/it/smartcommunitylab/aac/attributes/base/AbstractAttributes.java +++ b/src/main/java/it/smartcommunitylab/aac/attributes/base/AbstractAttributes.java @@ -16,6 +16,7 @@ package it.smartcommunitylab.aac.attributes.base; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonSubTypes.Type; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -29,7 +30,8 @@ * * all implementations should derive from this */ -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type") +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", defaultImpl = DefaultAttributesImpl.class) @JsonSubTypes({ @Type(value = DefaultAttributesImpl.class, name = SystemKeys.RESOURCE_ATTRIBUTES) }) public abstract class AbstractAttributes extends AbstractBaseUserResource implements UserAttributes { diff --git a/src/main/java/it/smartcommunitylab/aac/attributes/base/BaseAttributeSet.java b/src/main/java/it/smartcommunitylab/aac/attributes/base/BaseAttributeSet.java new file mode 100644 index 000000000..afa7efec4 --- /dev/null +++ b/src/main/java/it/smartcommunitylab/aac/attributes/base/BaseAttributeSet.java @@ -0,0 +1,27 @@ +/** + * Copyright 2024 the original author or authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package it.smartcommunitylab.aac.attributes.base; + +import it.smartcommunitylab.aac.attributes.model.AttributeSet; + +public abstract class BaseAttributeSet implements AttributeSet { + + public String getId() { + return getIdentifier(); + } + +} \ No newline at end of file diff --git a/src/main/java/it/smartcommunitylab/aac/attributes/controller/BaseAttributeProviderController.java b/src/main/java/it/smartcommunitylab/aac/attributes/controller/BaseAttributeProviderController.java index 5f38027c7..4d3182d82 100644 --- a/src/main/java/it/smartcommunitylab/aac/attributes/controller/BaseAttributeProviderController.java +++ b/src/main/java/it/smartcommunitylab/aac/attributes/controller/BaseAttributeProviderController.java @@ -22,6 +22,7 @@ import it.smartcommunitylab.aac.SystemKeys; import it.smartcommunitylab.aac.attributes.AttributeProviderManager; import it.smartcommunitylab.aac.attributes.model.ConfigurableAttributeProvider; +import it.smartcommunitylab.aac.attributes.service.AttributeProviderAuthorityService; import it.smartcommunitylab.aac.common.NoSuchAuthorityException; import it.smartcommunitylab.aac.common.NoSuchProviderException; import it.smartcommunitylab.aac.common.NoSuchRealmException; @@ -60,6 +61,9 @@ public class BaseAttributeProviderController implements InitializingBean { protected AttributeProviderManager providerManager; + // TODO evaluate replace with authorityManager + protected AttributeProviderAuthorityService authorityService; + @Override public void afterPropertiesSet() throws Exception { Assert.notNull(providerManager, "provider manager is required"); @@ -70,10 +74,30 @@ public void setProviderManager(AttributeProviderManager providerManager) { this.providerManager = providerManager; } + + @Autowired + public void setAuthorityService(AttributeProviderAuthorityService authorityService) { + this.authorityService = authorityService; + } + public String getAuthority() { return Config.R_USER; } + /* + * Authorities + * + * TODO evaluate returning a authority model as result + */ + @GetMapping("/aps/{realm}/authorities") + @Operation(summary = "list aps authorities from a given realm") + public Collection listAuthorities( + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm + ) throws NoSuchRealmException { + logger.debug("list idp authorities for realm {}", StringUtils.trimAllWhitespace(realm)); + return authorityService.getAuthorities().stream().map(a -> a.getAuthorityId()).collect(Collectors.toList()); + } + /* * Attribute providers * diff --git a/src/main/java/it/smartcommunitylab/aac/attributes/model/DefaultAttributesImpl.java b/src/main/java/it/smartcommunitylab/aac/attributes/model/DefaultAttributesImpl.java index 223bd11db..741c431c6 100644 --- a/src/main/java/it/smartcommunitylab/aac/attributes/model/DefaultAttributesImpl.java +++ b/src/main/java/it/smartcommunitylab/aac/attributes/model/DefaultAttributesImpl.java @@ -80,6 +80,10 @@ public String getIdentifier() { return identifier; } + public String getId() { + return identifier; + } + public String getName() { return name; } diff --git a/src/main/java/it/smartcommunitylab/aac/attributes/model/DefaultUserAttributesImpl.java b/src/main/java/it/smartcommunitylab/aac/attributes/model/DefaultUserAttributesImpl.java index 38f45c28c..6d3c3f002 100644 --- a/src/main/java/it/smartcommunitylab/aac/attributes/model/DefaultUserAttributesImpl.java +++ b/src/main/java/it/smartcommunitylab/aac/attributes/model/DefaultUserAttributesImpl.java @@ -81,6 +81,20 @@ public String getIdentifier() { return identifier; } + // local attributes identifier, for this set for this user + @Override + public String getId() { + if (getIdentifier() == null || getUserId() == null) { + return null; + } + + StringBuilder sb = new StringBuilder(); + sb.append(getUserId()).append(SystemKeys.URN_SEPARATOR); + sb.append(getIdentifier()); + + return sb.toString(); + } + public Collection getAttributes() { return attributes; } diff --git a/src/main/java/it/smartcommunitylab/aac/audit/controller/BaseAuditController.java b/src/main/java/it/smartcommunitylab/aac/audit/controller/BaseAuditController.java index 616d03823..91cdcca7d 100644 --- a/src/main/java/it/smartcommunitylab/aac/audit/controller/BaseAuditController.java +++ b/src/main/java/it/smartcommunitylab/aac/audit/controller/BaseAuditController.java @@ -21,8 +21,8 @@ import it.smartcommunitylab.aac.SystemKeys; import it.smartcommunitylab.aac.audit.AuditManager; import it.smartcommunitylab.aac.common.NoSuchRealmException; -import java.util.Collection; import java.util.Date; +import java.util.List; import java.util.Optional; import javax.validation.Valid; import javax.validation.constraints.NotNull; @@ -34,6 +34,7 @@ import org.springframework.boot.actuate.audit.AuditEvent; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.support.PageableExecutionUtils; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.util.Assert; @@ -42,6 +43,8 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; +import com.fasterxml.jackson.annotation.JsonUnwrapped; + /* * Base controller for audit */ @@ -67,26 +70,27 @@ public String getAuthority() { return Config.R_USER; } - @GetMapping("/audit/{realm}") - @Operation(summary = "find audit events from a given realm") - public Collection findEvents( - @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, - @RequestParam(required = false, name = "type") Optional type, - @RequestParam(required = false, name = "after") @DateTimeFormat( - iso = DateTimeFormat.ISO.DATE_TIME - ) Optional after, - @RequestParam(required = false, name = "before") @DateTimeFormat( - iso = DateTimeFormat.ISO.DATE_TIME - ) Optional before - ) throws NoSuchRealmException { - logger.debug("find audit events for realm {}", StringUtils.trimAllWhitespace(realm)); + // @GetMapping("/audit/{realm}") + // @Operation(summary = "find audit events from a given realm") + // public Collection findEvents( + // @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, + // @RequestParam(required = false, name = "type") Optional type, + // @RequestParam(required = false, name = "after") @DateTimeFormat( + // iso = DateTimeFormat.ISO.DATE_TIME + // ) Optional after, + // @RequestParam(required = false, name = "before") @DateTimeFormat( + // iso = DateTimeFormat.ISO.DATE_TIME + // ) Optional before + // ) throws NoSuchRealmException { + // logger.debug("find audit events for realm {}", StringUtils.trimAllWhitespace(realm)); - return auditManager.findRealmEvents(realm, type.orElse(null), after.orElse(null), before.orElse(null)); - } + // return auditManager.findRealmEvents(realm, type.orElse(null), after.orElse(null), before.orElse(null)); + // } - @GetMapping("/audit/{realm}/search") + // @GetMapping("/audit/{realm}/search") + @GetMapping("/audit/{realm}") @Operation(summary = "find audit events from a given realm") - public Page searchEvents( + public Page searchEvents( @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, @RequestParam(required = false, name = "type") Optional type, @RequestParam(required = false, name = "after") @DateTimeFormat( @@ -95,10 +99,45 @@ public Page searchEvents( @RequestParam(required = false, name = "before") @DateTimeFormat( iso = DateTimeFormat.ISO.DATE_TIME ) Optional before, + @RequestParam(required = false) String principal, Pageable pageRequest ) throws NoSuchRealmException { logger.debug("find audit events for realm {}", StringUtils.trimAllWhitespace(realm)); + if(principal != null) { + List events = auditManager.findPrincipalEvents(realm, principal, type.orElse(null), after.orElse(null), before.orElse(null)); + return PageableExecutionUtils.getPage( + events.stream().map(a -> new AuditEntry(a)).toList(), + pageRequest, + () -> events.size() + ); + } + + + Page page = auditManager.searchRealmEvents(realm, type.orElse(null), after.orElse(null), before.orElse(null), pageRequest); + + return PageableExecutionUtils.getPage( + page.getContent().stream().map(a -> new AuditEntry(a)).toList(), + pageRequest, + () -> page.getTotalElements() + ); + } + + + + public class AuditEntry { + @JsonUnwrapped + private AuditEvent event; + + public String getId() { + return event != null ? event.getTimestamp().toString() : null; + } - return auditManager.searchRealmEvents(realm, type.orElse(null), after.orElse(null), before.orElse(null), pageRequest); + public AuditEntry(AuditEvent event) { + this.event = event; + } + + public AuditEvent getEvent() { + return event; + } } } diff --git a/src/main/java/it/smartcommunitylab/aac/bootstrap/AACBootstrap.java b/src/main/java/it/smartcommunitylab/aac/bootstrap/AACBootstrap.java index 51d703fb9..6958401a8 100644 --- a/src/main/java/it/smartcommunitylab/aac/bootstrap/AACBootstrap.java +++ b/src/main/java/it/smartcommunitylab/aac/bootstrap/AACBootstrap.java @@ -424,7 +424,7 @@ public void bootstrapConfig() { } else { logger.debug("update realm {}", r.getSlug()); - // skip config maps + // config maps // TODO put in dedicated providers + config realm = realmService.updateRealm( @@ -433,9 +433,10 @@ public void bootstrapConfig() { r.getEmail(), r.isEditable(), r.isPublic(), - null, - null, - null + r.getOAuthConfiguration() != null ? r.getOAuthConfiguration().getConfiguration() : null, + r.getTosConfiguration() != null ? r.getTosConfiguration().getConfiguration() : null, + r.getLocalizationConfiguration() != null ? r.getLocalizationConfiguration().getConfiguration() : null, + r.getTemplatesConfiguration() != null ? r.getTemplatesConfiguration().getConfiguration() : null ); } diff --git a/src/main/java/it/smartcommunitylab/aac/clients/ClientManager.java b/src/main/java/it/smartcommunitylab/aac/clients/ClientManager.java index 014eb6606..011d807b0 100644 --- a/src/main/java/it/smartcommunitylab/aac/clients/ClientManager.java +++ b/src/main/java/it/smartcommunitylab/aac/clients/ClientManager.java @@ -30,9 +30,11 @@ import it.smartcommunitylab.aac.core.auth.RealmGrantedAuthority; import it.smartcommunitylab.aac.core.model.Client; import it.smartcommunitylab.aac.core.service.SubjectService; +import it.smartcommunitylab.aac.groups.service.GroupService; import it.smartcommunitylab.aac.identity.model.ConfigurableIdentityProvider; import it.smartcommunitylab.aac.identity.service.IdentityProviderService; import it.smartcommunitylab.aac.model.ClientApp; +import it.smartcommunitylab.aac.model.Group; import it.smartcommunitylab.aac.model.Realm; import it.smartcommunitylab.aac.model.RealmRole; import it.smartcommunitylab.aac.model.SpaceRole; @@ -105,6 +107,9 @@ public class ClientManager { @Autowired private SubjectRoleService subjectRoleService; + @Autowired + private GroupService groupService; + @Autowired private SubjectService subjectService; @@ -171,6 +176,9 @@ public Collection listClientApps(String realm, String type) throws No Collection roles = loadClientRoles(realm, app.getClientId()); app.setRealmRoles(roles); + Collection groups = loadClientGroups(realm, app.getClientId()); + app.setGroups(groups); + // load authorities Collection authorities = loadClientAuthorities(realm, app.getClientId()); app.setAuthorities(authorities); @@ -215,6 +223,9 @@ public Page searchClientApps(String realm, String keywords, Pageable Collection roles = loadClientRoles(realm, clientApp.getClientId()); clientApp.setRealmRoles(roles); + Collection groups = loadClientGroups(realm, clientApp.getClientId()); + clientApp.setGroups(groups); + // load authorities Collection authorities = loadClientAuthorities( realm, @@ -263,6 +274,9 @@ public ClientApp findClientApp(String realm, String clientId) { // load realm roles Collection roles = loadClientRoles(realm, clientApp.getClientId()); clientApp.setRealmRoles(roles); + + Collection groups = loadClientGroups(realm, clientApp.getClientId()); + clientApp.setGroups(groups); } catch (NoSuchClientException e) {} return clientApp; @@ -305,6 +319,9 @@ public ClientApp getClientApp(String realm, String clientId) throws NoSuchClient Collection roles = loadClientRoles(realm, clientApp.getClientId()); clientApp.setRealmRoles(roles); + Collection groups = loadClientGroups(realm, clientApp.getClientId()); + clientApp.setGroups(groups); + Collection spaceRoles = loadClientSpaceRoles(realm, clientApp.getClientId()); clientApp.setSpaceRoles(spaceRoles); @@ -361,6 +378,9 @@ public ClientApp registerClientApp(String realm, ClientApp app) throws NoSuchRea // load realm roles Collection roles = loadClientRoles(realm, clientApp.getClientId()); clientApp.setRealmRoles(roles); + + Collection groups = loadClientGroups(realm, clientApp.getClientId()); + clientApp.setGroups(groups); } catch (NoSuchClientException e) {} return clientApp; @@ -410,9 +430,27 @@ public ClientApp updateClientApp(String realm, String clientId, ClientApp app) throw new IllegalArgumentException("invalid client type"); } - // load realm roles - Collection roles = loadClientRoles(realm, clientApp.getClientId()); - clientApp.setRealmRoles(roles); + //update roles if defined + if(app.getRealmRoles() != null) { + //replace roles + Collection roles = realmRoleService.setRoles(clientId, realm, app.getRealmRoles().stream().map(RealmRole::getRole).toList()); + clientApp.setRealmRoles(new HashSet<>(roles)); + } else { + // load realm roles + Collection roles = loadClientRoles(realm, clientApp.getClientId()); + clientApp.setRealmRoles(roles); + } + + //update groups if defined + if(app.getGroups() != null) { + //replace groups + Collection groups = groupService.setSubjectGroups(clientId, realm, app.getGroups().stream().map(Group::getGroup).toList()); + clientApp.setGroups(groups); + } else { + //load groups + Collection groups = loadClientGroups(realm, clientApp.getClientId()); + clientApp.setGroups(groups); + } return clientApp; } @@ -919,6 +957,11 @@ private Collection loadClientRoles(String realm, String clientId) thr // .collect(Collectors.toSet()); } + private Collection loadClientGroups(String realm, String clientId) throws NoSuchClientException { + return groupService.getSubjectGroups(clientId, realm); + } + + private Collection loadClientSpaceRoles(String realm, String clientId) throws NoSuchClientException { return spaceRoleService.getRoles(clientId); } diff --git a/src/main/java/it/smartcommunitylab/aac/clients/controller/BaseClientAppController.java b/src/main/java/it/smartcommunitylab/aac/clients/controller/BaseClientAppController.java index 1f5808590..334a16864 100644 --- a/src/main/java/it/smartcommunitylab/aac/clients/controller/BaseClientAppController.java +++ b/src/main/java/it/smartcommunitylab/aac/clients/controller/BaseClientAppController.java @@ -27,8 +27,12 @@ import it.smartcommunitylab.aac.common.NoSuchRealmException; import it.smartcommunitylab.aac.model.ClientApp; import java.io.Serializable; +import java.util.Arrays; import java.util.Collection; +import java.util.HashSet; import java.util.Map; +import java.util.Set; + import javax.validation.Valid; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; @@ -37,6 +41,9 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.support.PageableExecutionUtils; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -46,6 +53,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; /* * Base controller for client app @@ -77,12 +85,27 @@ public String getAuthority() { @GetMapping("/apps/{realm}") @Operation(summary = "list client apps from a given realm") - public Collection listClientApp( - @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm + public Page listClientApp( + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, + @RequestParam(required = false) String q, + @RequestParam(required = false) String[] providers, + Pageable pageRequest ) throws NoSuchRealmException { logger.debug("list client apps for realm {}", StringUtils.trimAllWhitespace(realm)); - - return clientManager.listClientApps(realm); + + if(providers == null || providers.length == 0) { + return clientManager.searchClientApps(realm, q, pageRequest); + } else { + //manually filter, breaks pagination + Set ps = new HashSet<>(Arrays.asList(providers)); + Page page = clientManager.searchClientApps(realm, q, pageRequest); + return PageableExecutionUtils.getPage( + page.getContent().stream().filter(a -> Arrays.asList(a.getProviders()).stream().anyMatch(p -> ps.contains(p))).toList(), + pageRequest, + () -> page.getTotalElements() + ); + + } } @GetMapping("/apps/{realm}/{clientId}") diff --git a/src/main/java/it/smartcommunitylab/aac/config/AuditConfig.java b/src/main/java/it/smartcommunitylab/aac/config/AuditConfig.java index 0f4dc41cc..9fc02869e 100644 --- a/src/main/java/it/smartcommunitylab/aac/config/AuditConfig.java +++ b/src/main/java/it/smartcommunitylab/aac/config/AuditConfig.java @@ -31,6 +31,7 @@ import it.smartcommunitylab.aac.oauth.event.OAuth2EventPublisher; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; @@ -51,6 +52,7 @@ public class AuditConfig { @Autowired + @Qualifier("jdbcAuditDataSource") private DataSource dataSource; @Value("${audit.issuer}") diff --git a/src/main/java/it/smartcommunitylab/aac/config/DatabaseConfig.java b/src/main/java/it/smartcommunitylab/aac/config/DatabaseConfig.java index baebf9fac..d14297209 100644 --- a/src/main/java/it/smartcommunitylab/aac/config/DatabaseConfig.java +++ b/src/main/java/it/smartcommunitylab/aac/config/DatabaseConfig.java @@ -105,6 +105,21 @@ public HikariDataSource jdbcDataSource(@Qualifier("jdbcProperties") JdbcProperti return new HikariDataSource(config); } + @Bean(name = "jdbcAuditDataSource") + public DataSource jdbcAuditDataSource( + @Qualifier("auditJdbcProperties") JdbcProperties auditJdbcProperties, + @Qualifier("jdbcProperties") JdbcProperties jdbcProperties, + @Qualifier("jdbcDataSource") DataSource jdbcDataSource + ) throws PropertyVetoException { + if (auditJdbcProperties.equals(jdbcProperties)) { + return jdbcDataSource; + } + + HikariConfig config = buildDataSourceConfig(auditJdbcProperties); + config.setPoolName("jdbcAuditConnectionPool"); + return new HikariDataSource(config); + } + @Primary @Bean(name = "jpaDataSource") public HikariDataSource jpaDataSource(@Qualifier("jdbcProperties") JdbcProperties properties) @@ -177,7 +192,7 @@ public JpaTransactionManager getTransactionManager(EntityManagerFactory entityMa @Bean(name = "coreJdbcDataSourceInitializer") public JdbcDataSourceInitializer jdbcDataSourceInitializer( @Qualifier("jdbcDataSource") DataSource dataSource, - JdbcProperties properties + @Qualifier("jdbcProperties") JdbcProperties properties ) { return new JdbcDataSourceInitializer(dataSource, properties); } @@ -185,7 +200,7 @@ public JdbcDataSourceInitializer jdbcDataSourceInitializer( @Bean(name = "oauth2JdbcDataSourceInitializer") public JdbcDataSourceInitializer oauth2DataSourceInitializer( @Qualifier("jdbcDataSource") DataSource dataSource, - JdbcProperties properties + @Qualifier("jdbcProperties") JdbcProperties properties ) { return new JdbcDataSourceInitializer(dataSource, properties, "classpath:db/sql/oauth2/schema-@@platform@@.sql"); } @@ -193,8 +208,8 @@ public JdbcDataSourceInitializer oauth2DataSourceInitializer( //TODO add optional ObjectProvider to support separated dataSource for audit @Bean(name = "auditJdbcDataSourceInitializer") public JdbcDataSourceInitializer auditDataSourceInitializer( - @Qualifier("jdbcDataSource") DataSource dataSource, - JdbcProperties properties + @Qualifier("jdbcAuditDataSource") DataSource dataSource, + @Qualifier("auditJdbcProperties") JdbcProperties properties ) { return new JdbcDataSourceInitializer(dataSource, properties, "classpath:db/sql/audit/schema-@@platform@@.sql"); } diff --git a/src/main/java/it/smartcommunitylab/aac/config/JdbcProperties.java b/src/main/java/it/smartcommunitylab/aac/config/JdbcProperties.java index b315c8b0e..2b6b20819 100644 --- a/src/main/java/it/smartcommunitylab/aac/config/JdbcProperties.java +++ b/src/main/java/it/smartcommunitylab/aac/config/JdbcProperties.java @@ -17,6 +17,7 @@ package it.smartcommunitylab.aac.config; import java.util.Map; +import java.util.Objects; import org.springframework.boot.sql.init.DatabaseInitializationMode; public class JdbcProperties { @@ -168,4 +169,45 @@ public Map getDataSourceProperties() { public void setDataSourceProperties(Map dataSourceProperties) { this.dataSourceProperties = dataSourceProperties; } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + JdbcProperties that = (JdbcProperties) obj; + return ( + showSql == that.showSql && + maxPoolSize == that.maxPoolSize && + minPoolSize == that.minPoolSize && + idleTimeout == that.idleTimeout && + keepAliveTimeout == that.keepAliveTimeout && + connectionTimeout == that.connectionTimeout && + Objects.equals(driver, that.driver) && + Objects.equals(dialect, that.dialect) && + Objects.equals(url, that.url) && + Objects.equals(user, that.user) && + Objects.equals(password, that.password) + ); + } + + @Override + public int hashCode() { + return Objects.hash( + driver, + dialect, + url, + user, + password, + showSql, + maxPoolSize, + minPoolSize, + idleTimeout, + keepAliveTimeout, + connectionTimeout + ); + } } diff --git a/src/main/java/it/smartcommunitylab/aac/config/PropertiesConfig.java b/src/main/java/it/smartcommunitylab/aac/config/PropertiesConfig.java index 05fc6c69b..fac27abb2 100644 --- a/src/main/java/it/smartcommunitylab/aac/config/PropertiesConfig.java +++ b/src/main/java/it/smartcommunitylab/aac/config/PropertiesConfig.java @@ -37,6 +37,12 @@ public JdbcProperties jdbcProps() { return new JdbcProperties(); } + @Bean(name = "auditJdbcProperties") + @ConfigurationProperties(prefix = "audit.jdbc") + public JdbcProperties jdbcAuditProps() { + return new JdbcProperties(); + } + @Bean @ConfigurationProperties(prefix = "authorities.identity") public IdentityAuthoritiesProperties identityAuthoritiesProps() { diff --git a/src/main/java/it/smartcommunitylab/aac/config/WebConfig.java b/src/main/java/it/smartcommunitylab/aac/config/WebConfig.java index 8fd3ef9c7..963f4cd6f 100644 --- a/src/main/java/it/smartcommunitylab/aac/config/WebConfig.java +++ b/src/main/java/it/smartcommunitylab/aac/config/WebConfig.java @@ -157,5 +157,23 @@ public void addResourceHandlers(ResourceHandlerRegistry registry) { .resourceChain(true) .addResolver(new EncodedResourceResolver()) .addResolver(new PathResourceResolver()); + + // dev console + registry + .addResourceHandler("/console/dev/**") + .addResourceLocations("classpath:/console/dev/") + .setCachePeriod(60 * 60 * 24 * 365)/* one year */ + .resourceChain(true) + .addResolver(new EncodedResourceResolver()) + .addResolver(new PathResourceResolver()); + + // admin console + registry + .addResourceHandler("/console/admin/**") + .addResourceLocations("classpath:/console/admin/") + .setCachePeriod(60 * 60 * 24 * 365)/* one year */ + .resourceChain(true) + .addResolver(new EncodedResourceResolver()) + .addResolver(new PathResourceResolver()); } } diff --git a/src/main/java/it/smartcommunitylab/aac/console/AdminController.java b/src/main/java/it/smartcommunitylab/aac/console/AdminController.java index 3a150f0c7..f2dd33c8f 100644 --- a/src/main/java/it/smartcommunitylab/aac/console/AdminController.java +++ b/src/main/java/it/smartcommunitylab/aac/console/AdminController.java @@ -16,66 +16,227 @@ package it.smartcommunitylab.aac.console; +import com.fasterxml.jackson.annotation.JsonUnwrapped; import io.swagger.v3.oas.annotations.Hidden; import it.smartcommunitylab.aac.Config; import it.smartcommunitylab.aac.SystemKeys; import it.smartcommunitylab.aac.common.NoSuchRealmException; import it.smartcommunitylab.aac.common.RegistrationException; +import it.smartcommunitylab.aac.config.ApplicationProperties; import it.smartcommunitylab.aac.model.Realm; import it.smartcommunitylab.aac.realms.RealmManager; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.metrics.MetricsEndpoint; +import org.springframework.boot.actuate.metrics.MetricsEndpoint.MetricResponse; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Order; +import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; @RestController -@Validated @Hidden @PreAuthorize("hasAuthority('" + Config.R_ADMIN + "')") +@RequestMapping("/console/admin") public class AdminController { + private static final String[] SORT_WHITELIST = { "slug", "name" }; + + // @formatter:off + private static final String[] METRICS_KEYS = { + "jvm.memory.used", "jvm.memory.max", + "jvm.threads.live", "jvm.threads.daemon", "jvm.threads.peak", + "hikaricp.connections", "hikaricp.connections.max", "hikaricp.connections.min", "hikaricp.connections.usage", + "http.server.requests", + "process.cpu.usage","process.uptime","process.files.open","process.files.max", + "system.cpu.count", "system.cpu.usage", "system.load.average.1m", + "tomcat.sessions.active.current", "tomcat.sessions.active.max", "tomcat.sessions.alive.max", "tomcat.sessions.created", + "tomcat.sessions.expired", "tomcat.sessions.rejected" + }; + + // @formatter:on + + @Autowired(required = false) + private MetricsEndpoint metrics; + + @Autowired + private ApplicationProperties appProps; + @Autowired private RealmManager realmManager; - @GetMapping("/console/admin/realms") + @GetMapping( + value = { + "/", + "/{path:^(?!\\S+(?:\\.[a-z0-9]{2,}))\\S+$}", + "/-/**", + } + ) + public ModelAndView console(HttpServletRequest request) { + String requestUrl = ServletUriComponentsBuilder + .fromRequestUri(request) + .replacePath(request.getContextPath()) + .build() + .toUriString(); + + String applicationUrl = StringUtils.hasText(appProps.getUrl()) + ? appProps.getUrl() + : requestUrl; + + //build config + Map config = new HashMap<>(); + config.put("REACT_APP_APPLICATION_URL", applicationUrl); + config.put("REACT_APP_API_URL", applicationUrl); + config.put("REACT_APP_CONTEXT_PATH", "/console/admin/"); + + config.put("REACT_APP_NAME", appProps.getName()); + + // model.addAttribute("config", config); + return new ModelAndView("console/admin", Collections.singletonMap("config",config)); + } + + + @GetMapping("/props") + public ResponseEntity appProps() { + return ResponseEntity.ok(appProps); + } + + @GetMapping("/metrics") + public ResponseEntity> metrics() { + if(metrics == null) { + return ResponseEntity.ok(Collections.emptyList()); + } + + List values = Arrays + .asList(METRICS_KEYS) + .stream() + .map(k -> new SystemMetric(k, metrics.metric(k, null))) + .collect(Collectors.toList()); + return ResponseEntity.ok(values); + } + + @GetMapping("/metrics/{id}") + public ResponseEntity metric( + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String id + ) { + if(metrics == null) { + return ResponseEntity.notFound().build(); + } + + MetricResponse metric = metrics.metric(id, null); + return ResponseEntity.ok(new SystemMetric(id, metric)); + } + + /* + * Realms + */ + + @GetMapping("/realms") public Page getRealms(@RequestParam(required = false) String q, Pageable pageRequest) { - return realmManager.searchRealms(q, pageRequest); + // fix pageable unsupported sort via whitelist + // also sort with slug by default + List orders = pageRequest + .getSort() + .filter(o -> Arrays.asList(SORT_WHITELIST).contains(o.getProperty())) + .toList(); + Sort sort = orders.isEmpty() ? Sort.by("slug") : Sort.by(orders); + Pageable pg = PageRequest.of(pageRequest.getPageNumber(), pageRequest.getPageSize(), sort); + + return realmManager.searchRealms(q, pg); } - @GetMapping("/console/admin/realms/{slug}") + @GetMapping("/realms/{slug}") public Realm getRealm(@PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String slug) throws NoSuchRealmException { - return realmManager.getRealm(slug); + Realm realm = realmManager.getRealm(slug); + // make sure config is clear + realm.clearConfig(); + + return realm; } - @PostMapping("/console/admin/realms") - public Realm addRealm(@RequestBody @Valid @NotNull Realm realm) throws RegistrationException { - return realmManager.addRealm(realm); + @PostMapping("/realms") + public Realm addRealm(@RequestBody @Valid @NotNull Realm reg) throws RegistrationException { + return realmManager.addRealm(reg); } - @PutMapping("/console/admin/realms/{slug}") + @PutMapping("/realms/{slug}") public Realm updateRealm( @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String slug, - @RequestBody @Valid @NotNull Realm realm + @RequestBody @Valid @NotNull Realm reg ) throws NoSuchRealmException, RegistrationException { - return realmManager.updateRealm(slug, realm); + + Realm realm = realmManager.getRealm(slug); + + //keep config, not modifiable via admin console + reg.setOAuthConfiguration(realm.getOAuthConfiguration()); + reg.setLocalizationConfiguration(realm.getLocalizationConfiguration()); + reg.setTemplatesConfiguration(realm.getTemplatesConfiguration()); + reg.setTosConfiguration(realm.getTosConfiguration()); + + //update + realm = realmManager.updateRealm(slug, reg); + // make sure config is clear + realm.clearConfig(); + + return realm; } - @DeleteMapping("/console/admin/realms/{slug}") + @DeleteMapping("/realms/{slug}") public void deleteRealm(@PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String slug) throws NoSuchRealmException { realmManager.deleteRealm(slug, true); } + + public static class SystemMetric { + + private final String id; + + @JsonUnwrapped + private final MetricResponse metric; + + public SystemMetric(String id, MetricResponse metric) { + this.id = id; + this.metric = metric; + } + + public MetricResponse getMetric() { + return metric; + } + + public String getId() { + return id; + } + + public MetricsEndpoint.Sample getSample() { + return metric != null && metric.getMeasurements() != null + ? metric.getMeasurements().stream().findFirst().orElse(null) + : null; + } + } } diff --git a/src/main/java/it/smartcommunitylab/aac/console/DevClientAppController.java b/src/main/java/it/smartcommunitylab/aac/console/DevClientAppController.java index c9b2a26df..32a875243 100644 --- a/src/main/java/it/smartcommunitylab/aac/console/DevClientAppController.java +++ b/src/main/java/it/smartcommunitylab/aac/console/DevClientAppController.java @@ -313,6 +313,7 @@ public ResponseEntity> updateRealmAppAuthorities( // filter roles, make sure they belong to the current realm Set values = roles .stream() + .filter(a -> a.getRole() != null ) .filter(a -> a.getRealm() == null || realm.equals(a.getRealm())) .map(a -> a.getRole()) .collect(Collectors.toSet()); diff --git a/src/main/java/it/smartcommunitylab/aac/console/DevConsoleController.java b/src/main/java/it/smartcommunitylab/aac/console/DevConsoleController.java new file mode 100644 index 000000000..5bf1d3ec1 --- /dev/null +++ b/src/main/java/it/smartcommunitylab/aac/console/DevConsoleController.java @@ -0,0 +1,169 @@ +package it.smartcommunitylab.aac.console; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.support.PageableExecutionUtils; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import io.swagger.v3.oas.annotations.Hidden; +import it.smartcommunitylab.aac.Config; +import it.smartcommunitylab.aac.SystemKeys; +import it.smartcommunitylab.aac.common.NoSuchRealmException; +import it.smartcommunitylab.aac.common.RegistrationException; +import it.smartcommunitylab.aac.config.ApplicationProperties; +import it.smartcommunitylab.aac.core.auth.RealmGrantedAuthority; +import it.smartcommunitylab.aac.core.auth.UserAuthentication; +import it.smartcommunitylab.aac.model.Realm; +import it.smartcommunitylab.aac.realms.RealmManager; +import it.smartcommunitylab.aac.users.MyUserManager; +import it.smartcommunitylab.aac.users.UserManager; + +@RestController +@Hidden +@PreAuthorize("hasAuthority('" + Config.R_USER + "')") +@RequestMapping("/console/dev") +public class DevConsoleController { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Value("${application.url}") + private String applicationUrl; + + @Autowired + private ApplicationProperties appProps; + + @Autowired + private MyUserManager myUserManager; + + @Autowired + private RealmManager realmManager; + + @Autowired + private UserManager userManager; + + @GetMapping( + value = { + "/", + "/{path:^(?!\\S+(?:\\.[a-z0-9]{2,}))\\S+$}", + "/-/**", + } + ) + public ModelAndView console(HttpServletRequest request) { + String requestUrl = ServletUriComponentsBuilder + .fromRequestUri(request) + .replacePath(request.getContextPath()) + .build() + .toUriString(); + + String applicationUrl = StringUtils.hasText(appProps.getUrl()) + ? appProps.getUrl() + : requestUrl; + + //build config + Map config = new HashMap<>(); + config.put("REACT_APP_APPLICATION_URL", applicationUrl); + config.put("REACT_APP_API_URL", applicationUrl); + config.put("REACT_APP_CONTEXT_PATH", "/console/dev/"); + + config.put("VITE_APP_NAME", appProps.getName()); + + // model.addAttribute("config", config); + return new ModelAndView("console/dev", Collections.singletonMap("config",config)); + } + + + @GetMapping("/myrealms") + public Page myRealms( + UserAuthentication auth, + @RequestParam(required = false) String q, + Pageable pageRequest + ) { + List realms = new ArrayList<>(); + boolean isAdmin = auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals(Config.R_ADMIN)); + + if (isAdmin) { + realms = (List) realmManager.listRealms(); + } else { + Set realmsIds = auth.getAuthorities().stream().filter(RealmGrantedAuthority.class::isInstance) + .map(a -> (RealmGrantedAuthority) a).filter(a -> a.getRole().equals(Config.R_DEVELOPER)) + .map(a -> (a.getRealm())).collect(Collectors.toSet()); + for (String id : realmsIds) { + Realm temp = realmManager.findRealm(id); + if (temp != null) { + realms.add(temp); + } + } + } + + if(q != null) { + //filter + List list = realms.stream().filter(r -> (r.getSlug().toLowerCase().contains(q.toLowerCase()) || r.getName().toLowerCase().contains(q.toLowerCase()))).toList(); + return PageableExecutionUtils.getPage( + list, + pageRequest, + () -> list.size() + ); + } else { + List list = realms; + return PageableExecutionUtils.getPage( + list, + pageRequest, + () -> list.size() + ); + } + + } + + @GetMapping("/myrealms/{slug}") + public Realm getRealm(@PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String slug) + throws NoSuchRealmException { + return realmManager.getRealm(slug); + } + + @PostMapping("/myrealms") + public Realm addRealm(@RequestBody @Valid @NotNull Realm realm) throws RegistrationException { + return realmManager.addRealm(realm); + } + + @PutMapping("/myrealms/{slug}") + public Realm updateRealm(@PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String slug, + @RequestBody @Valid @NotNull Realm realm) throws NoSuchRealmException, RegistrationException { + return realmManager.updateRealm(slug, realm); + } + + @DeleteMapping("/myrealms/{slug}") + public void deleteRealm(@PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String slug) + throws NoSuchRealmException { + realmManager.deleteRealm(slug, true); + } + +} diff --git a/src/main/java/it/smartcommunitylab/aac/console/DevController.java b/src/main/java/it/smartcommunitylab/aac/console/DevController.java index 28997a6ae..e94b8344f 100644 --- a/src/main/java/it/smartcommunitylab/aac/console/DevController.java +++ b/src/main/java/it/smartcommunitylab/aac/console/DevController.java @@ -276,6 +276,21 @@ public ResponseEntity getRealmStats( }) .collect(Collectors.toList()); bean.setRegistrationEvents(registrationEvents); + + bean.setTokenCount(auditManager.countRealmEvents(realm, "OAUTH2_TOKEN_GRANT", after, null)); + List tokenEvents = auditManager + .searchRealmEvents(realm, "OAUTH2_TOKEN_GRANT", after, null, PageRequest.of(0, 5)) + .getContent() + .stream() + .map(e -> { + // clear event details + Map d = new HashMap<>(e.getData()); + d.remove("details"); + + return new AuditEvent(e.getTimestamp(), e.getPrincipal(), e.getType(), d); + }) + .collect(Collectors.toList()); + bean.setTokenEvents(tokenEvents); } return ResponseEntity.ok(bean); diff --git a/src/main/java/it/smartcommunitylab/aac/console/DevManager.java b/src/main/java/it/smartcommunitylab/aac/console/DevManager.java index 89c6b4f3f..688e6aecf 100644 --- a/src/main/java/it/smartcommunitylab/aac/console/DevManager.java +++ b/src/main/java/it/smartcommunitylab/aac/console/DevManager.java @@ -631,7 +631,13 @@ public String previewRealmTemplate( } // get custom style - String customStyle = templateAuthority.getProviderByRealm(realm).getConfig().getCustomStyle(); + // String customStyle = templateAuthority.getProviderByRealm(realm).getConfig().getCustomStyle(); + String customStyle = null; + // fetch custom style from config + if(r.getTemplatesConfiguration() != null && r.getTemplatesConfiguration().getCustomStyle() != null) { + customStyle = r.getTemplatesConfiguration().getCustomStyle(); + } + model.put("customStyle", customStyle); // Create the HTML body using Thymeleaf diff --git a/src/main/java/it/smartcommunitylab/aac/console/DevRealmController.java b/src/main/java/it/smartcommunitylab/aac/console/DevRealmController.java index dea5b604e..035a13489 100644 --- a/src/main/java/it/smartcommunitylab/aac/console/DevRealmController.java +++ b/src/main/java/it/smartcommunitylab/aac/console/DevRealmController.java @@ -34,23 +34,25 @@ import it.smartcommunitylab.aac.core.auth.UserAuthentication; import it.smartcommunitylab.aac.dto.RealmConfig; import it.smartcommunitylab.aac.dto.UserSubject; +import it.smartcommunitylab.aac.groups.GroupManager; import it.smartcommunitylab.aac.identity.IdentityProviderManager; import it.smartcommunitylab.aac.model.Developer; import it.smartcommunitylab.aac.model.Realm; import it.smartcommunitylab.aac.model.Subject; import it.smartcommunitylab.aac.realms.RealmManager; +import it.smartcommunitylab.aac.roles.RealmRoleManager; import it.smartcommunitylab.aac.services.ServicesManager; import it.smartcommunitylab.aac.templates.TemplatesManager; import it.smartcommunitylab.aac.templates.model.ConfigurableTemplateProvider; -import it.smartcommunitylab.aac.templates.provider.RealmTemplateProviderConfig; import it.smartcommunitylab.aac.templates.service.LanguageService; +import it.smartcommunitylab.aac.users.UserManager; + import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; import javax.servlet.ServletOutputStream; @@ -105,6 +107,15 @@ public class DevRealmController { @Autowired private TemplatesManager templatesManager; + @Autowired + private UserManager userManager; + + @Autowired + private GroupManager groupManager; + + @Autowired + private RealmRoleManager roleManager; + // @Autowired // private AuditManager auditManager; @@ -213,7 +224,7 @@ public void exportRealm( /* * Dev console users */ - @GetMapping("/realms/{realm}/developers") + @GetMapping(value = {"/realms/{realm}/developers", "/developers/{realm}"}) @PreAuthorize("hasAuthority('" + Config.R_ADMIN + "') or hasAuthority(#realm+':ROLE_ADMIN')") public Collection getDevelopers( @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm @@ -221,7 +232,7 @@ public Collection getDevelopers( return realmManager.getDevelopers(realm); } - @PostMapping("/realms/{realm}/developers") + @PostMapping(value = {"/realms/{realm}/developers", "/developers/{realm}"}) public Developer inviteDeveloper( @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, @RequestBody @Valid @NotNull UserSubject bean @@ -229,8 +240,19 @@ public Developer inviteDeveloper( return realmManager.inviteDeveloper(realm, bean.getSubjectId(), bean.getEmail()); } + @GetMapping(value = {"/realms/{realm}/developers/{subjectId}", "/developers/{realm}/{subjectId}"}) + @PreAuthorize("hasAuthority('" + Config.R_ADMIN + "') or hasAuthority(#realm+':ROLE_ADMIN')") + public Developer getDeveloper( + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String subjectId + ) throws NoSuchRealmException, NoSuchSubjectException { + return realmManager.getDevelopers(realm).stream() + .filter(d -> d.getSubjectId().equals(subjectId)) + .findFirst().orElseThrow(NoSuchSubjectException::new); + } + @PutMapping("/realms/{realm}/developers/{subjectId}") - public Developer updateDeveloper( + public Developer updateDeveloperRoles( @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String subjectId, @RequestBody @Valid @NotNull Collection roles @@ -238,7 +260,20 @@ public Developer updateDeveloper( return realmManager.updateDeveloper(realm, subjectId, roles); } - @DeleteMapping("/realms/{realm}/developers/{subjectId}") + @PutMapping("/developers/{realm}/{subjectId}") + public Developer updateDeveloper( + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String subjectId, + @RequestBody @Valid @NotNull Developer developer + ) throws NoSuchRealmException, NoSuchUserException { + Set roles = Collections.emptySet(); + if(developer.getAuthorities() != null) { + roles = new HashSet<>(developer.getAuthorities().stream().filter(a -> realm.equals(a.getRealm())).map(a -> a.getRole()).toList()); + } + + return realmManager.updateDeveloper(realm, subjectId, roles); + } + @DeleteMapping(value = {"/realms/{realm}/developers/{subjectId}", "/developers/{realm}/{subjectId}"}) public void removeDeveloper( @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String subjectId @@ -253,7 +288,9 @@ public void removeDeveloper( public Collection getRealmSubjects( @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, @RequestParam(required = false) String q, - @RequestParam(required = false) String t + @RequestParam(required = false) String t, + @RequestParam(required = false) String group, + @RequestParam(required = false) String role ) throws NoSuchRealmException { Set types = StringUtils.hasText(t) ? StringUtils.commaDelimitedListToSet(t) : null; return subjectManager.searchSubjects(realm, q, types); diff --git a/src/main/java/it/smartcommunitylab/aac/console/DevSubjectsController.java b/src/main/java/it/smartcommunitylab/aac/console/DevSubjectsController.java new file mode 100644 index 000000000..7f084e401 --- /dev/null +++ b/src/main/java/it/smartcommunitylab/aac/console/DevSubjectsController.java @@ -0,0 +1,151 @@ +/* + * Copyright 2023 the original author or authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package it.smartcommunitylab.aac.console; + +import io.swagger.v3.oas.annotations.Hidden; +import it.smartcommunitylab.aac.SystemKeys; +import it.smartcommunitylab.aac.common.NoSuchGroupException; +import it.smartcommunitylab.aac.common.NoSuchRealmException; +import it.smartcommunitylab.aac.common.NoSuchSubjectException; +import it.smartcommunitylab.aac.core.SubjectManager; +import it.smartcommunitylab.aac.groups.GroupManager; +import it.smartcommunitylab.aac.model.Subject; +import it.smartcommunitylab.aac.realms.RealmManager; +import it.smartcommunitylab.aac.roles.RealmRoleManager; +import it.smartcommunitylab.aac.templates.TemplatesManager; +import it.smartcommunitylab.aac.users.UserManager; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.util.StringUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Validated +@Hidden +@RequestMapping("/console/dev") +public class DevSubjectsController { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RealmManager realmManager; + + + + @Autowired + private SubjectManager subjectManager; + + @Autowired + private TemplatesManager templatesManager; + + @Autowired + private UserManager userManager; + + @Autowired + private GroupManager groupManager; + + @Autowired + private RealmRoleManager roleManager; + + + + + + /* + * Realm subjects + */ + @GetMapping("/subjects/{realm}") + public Page getRealmSubjects( + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, + @RequestParam(required = false) String q, + @RequestParam(required = false) String t, + @RequestParam(required = false) String group, + @RequestParam(required = false) String role, + Pageable pageRequest + ) throws NoSuchRealmException { + Set types = StringUtils.hasText(t) ? StringUtils.commaDelimitedListToSet(t) : null; + + if(group != null) { + //list members for group + List subjects = new ArrayList<>(); + long total = 0; + try { + String[] ids = groupManager.getGroupMembers(realm, group).toArray(new String[0]); + total = ids.length; + + for(int i = 0; i< ids.length; i++) { + if(pageRequest == null || (i >= pageRequest.getOffset() && i <=pageRequest.getOffset()+pageRequest.getPageSize())) { + try { + subjects.add(subjectManager.getSubject(realm, ids[i])); + } catch (NoSuchSubjectException nue) { + //skip, registration could be stale + } + } + } + + if (types != null) { + //filter + subjects = subjects.stream().filter(s -> types.contains(s.getType())).collect(Collectors.toList()); + } + } catch (NoSuchGroupException e) { + //ignore + } + return new PageImpl<>(subjects, pageRequest, total); + + } + + List subjects = subjectManager.searchSubjects(realm, q, types); + if(pageRequest == null ) { + return new PageImpl<>(subjects, pageRequest, subjects.size()); + } else { + int start = (int) Math.min(pageRequest.getOffset(),Integer.MAX_VALUE); + int end = (int) Math.min(pageRequest.getOffset()+pageRequest.getPageSize(), subjects.size()); + return new PageImpl<>(subjects.subList(start,end), pageRequest, subjects.size()); + } + + + + + } + + @GetMapping("/subjects/{realm}/{subjectId}") + public Subject getRealmSubject( + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String subjectId + ) throws NoSuchRealmException, NoSuchSubjectException { + return subjectManager.getSubject(realm, subjectId); + } + +} diff --git a/src/main/java/it/smartcommunitylab/aac/console/DevUsersController.java b/src/main/java/it/smartcommunitylab/aac/console/DevUsersController.java index 3f66cb824..c8ae02732 100644 --- a/src/main/java/it/smartcommunitylab/aac/console/DevUsersController.java +++ b/src/main/java/it/smartcommunitylab/aac/console/DevUsersController.java @@ -138,6 +138,7 @@ public ResponseEntity> updateUserAuthorities( // filter roles, make sure they belong to the current realm Set values = roles .stream() + .filter(a -> a.getRole() != null ) .filter(a -> a.getRealm() == null || realm.equals(a.getRealm())) .map(a -> a.getRole()) .collect(Collectors.toSet()); @@ -284,7 +285,7 @@ public ResponseEntity> getRealmUserApps( ) throws NoSuchRealmException, NoSuchUserException { Collection result = userManager.getConnectedApps(realm, userId); return ResponseEntity.ok(result); - } + } @DeleteMapping("/users/{realm}/{userId}/apps/{clientId}") public ResponseEntity revokeRealmUserApps( @@ -295,6 +296,32 @@ public ResponseEntity revokeRealmUserApps( userManager.deleteConnectedApp(realm, userId, clientId); return ResponseEntity.ok(null); } + + @GetMapping("/connectedapps/{realm}") + public ResponseEntity> getRealmConnectedApps( + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, + @RequestParam @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String subjectId + ) throws NoSuchRealmException, NoSuchUserException { + Collection result = userManager.getConnectedApps(realm, subjectId); + return ResponseEntity.ok(result); + } + + @DeleteMapping("/connectedapps/{realm}/{connectionId}") + public ResponseEntity deleteRealmUserApps( + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.RESOURCE_PATTERN) String connectionId + ) throws NoSuchRealmException, NoSuchUserException, NoSuchClientException { + String[] ids = connectionId.split(":"); + if(ids.length != 2) { + throw new IllegalArgumentException("invalid connection id"); + } + String userId = ids[0]; + String clientId = ids[1]; + + userManager.deleteConnectedApp(realm, userId, clientId); + return ResponseEntity.ok(null); + } + /* * Audit diff --git a/src/main/java/it/smartcommunitylab/aac/controller/HomeController.java b/src/main/java/it/smartcommunitylab/aac/controller/HomeController.java index 4b28cbb61..6e78d8ccc 100644 --- a/src/main/java/it/smartcommunitylab/aac/controller/HomeController.java +++ b/src/main/java/it/smartcommunitylab/aac/controller/HomeController.java @@ -53,13 +53,16 @@ public ModelAndView userConsole() { @RolesAllowed("ROLE_USER") @GetMapping("/console/dev") public ModelAndView devConsole() { - return new ModelAndView("redirect:/dev"); + // return new ModelAndView("redirect:/dev"); + return new ModelAndView("redirect:/console/dev/"); } @RolesAllowed("ROLE_USER") @GetMapping("/console/admin") public ModelAndView adminConsole() { - return new ModelAndView("redirect:/dev#/admin"); + // return new ModelAndView("redirect:/dev#/admin"); + // return new ModelAndView("forward:/console/admin/index.html"); + return new ModelAndView("redirect:/console/admin/"); } /* diff --git a/src/main/java/it/smartcommunitylab/aac/controller/LoginController.java b/src/main/java/it/smartcommunitylab/aac/controller/LoginController.java index 85a934208..3484af3db 100644 --- a/src/main/java/it/smartcommunitylab/aac/controller/LoginController.java +++ b/src/main/java/it/smartcommunitylab/aac/controller/LoginController.java @@ -240,10 +240,15 @@ public String login( // TODO refactor with proper provider + model List authorities = new ArrayList<>(); for (IdentityProvider idp : providers) { - LoginProvider a = idp.getLoginProvider(clientDetails, authorizationRequest); - // lp is optional - if (a != null) { - authorities.add(a); + try { + LoginProvider a = idp.getLoginProvider(clientDetails, authorizationRequest); + // lp is optional + if (a != null) { + authorities.add(a); + } + } catch (RuntimeException e) { + //skip problematic provider + logger.error("error with login provider {}: {}",idp.getProvider(), e.getMessage()); } } diff --git a/src/main/java/it/smartcommunitylab/aac/core/provider/config/ConfigurableProviderImpl.java b/src/main/java/it/smartcommunitylab/aac/core/provider/config/ConfigurableProviderImpl.java index a261604b9..d01513ad0 100644 --- a/src/main/java/it/smartcommunitylab/aac/core/provider/config/ConfigurableProviderImpl.java +++ b/src/main/java/it/smartcommunitylab/aac/core/provider/config/ConfigurableProviderImpl.java @@ -269,6 +269,10 @@ public Integer getVersion() { public void setVersion(Integer version) { this.version = version; } + + public String getId() { + return this.provider; + } @Override public String toString() { diff --git a/src/main/java/it/smartcommunitylab/aac/core/service/SubjectService.java b/src/main/java/it/smartcommunitylab/aac/core/service/SubjectService.java index d33407acb..d41d34cf6 100644 --- a/src/main/java/it/smartcommunitylab/aac/core/service/SubjectService.java +++ b/src/main/java/it/smartcommunitylab/aac/core/service/SubjectService.java @@ -188,7 +188,7 @@ public List searchSubjects(String realm, String q) { realm, q ) - : Collections.emptyList(); + : subjectRepository.findByRealm(realm); return subjects.stream().map(s -> toSubject(s)).collect(Collectors.toList()); } @@ -379,7 +379,7 @@ public List updateAuthorities(String uuid, String realm, Colle List oldRoles = authorityRepository.findBySubjectAndRealm(uuid, realm); // unpack roles - Set newRoles = roles + Set newRoles = roles == null ? Collections.emptySet() : roles .stream() .map(r -> { SubjectAuthorityEntity re = new SubjectAuthorityEntity(uuid); diff --git a/src/main/java/it/smartcommunitylab/aac/dto/RealmStats.java b/src/main/java/it/smartcommunitylab/aac/dto/RealmStats.java index 4ced9883d..1bee56597 100644 --- a/src/main/java/it/smartcommunitylab/aac/dto/RealmStats.java +++ b/src/main/java/it/smartcommunitylab/aac/dto/RealmStats.java @@ -19,11 +19,12 @@ import it.smartcommunitylab.aac.model.Realm; import java.util.List; import org.springframework.boot.actuate.audit.AuditEvent; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; -/** - * @author raman - * - */ +@JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) public class RealmStats { private Realm realm; @@ -40,6 +41,9 @@ public class RealmStats { private Long registrationCount; private List registrationEvents; + private Long tokenCount; + private List tokenEvents; + public Realm getRealm() { return realm; } @@ -127,4 +131,20 @@ public List getRegistrationEvents() { public void setRegistrationEvents(List registrationEvents) { this.registrationEvents = registrationEvents; } + + public Long getTokenCount() { + return tokenCount; + } + + public void setTokenCount(Long tokenCount) { + this.tokenCount = tokenCount; + } + + public List getTokenEvents() { + return tokenEvents; + } + + public void setTokenEvents(List tokenEvents) { + this.tokenEvents = tokenEvents; + } } diff --git a/src/main/java/it/smartcommunitylab/aac/groups/BaseGroupController.java b/src/main/java/it/smartcommunitylab/aac/groups/BaseGroupController.java index 9f12d342a..f9ba14e4b 100644 --- a/src/main/java/it/smartcommunitylab/aac/groups/BaseGroupController.java +++ b/src/main/java/it/smartcommunitylab/aac/groups/BaseGroupController.java @@ -36,6 +36,8 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.util.Assert; @@ -46,6 +48,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; /* * Base controller for realm groups @@ -85,12 +88,14 @@ public String getAuthority() { @GetMapping("/groups/{realm}") @Operation(summary = "list groups for realm") - public Collection getGroups( - @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm + public Page listGroups( + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, + @RequestParam(required = false) String q, + Pageable pageRequest ) throws NoSuchRealmException { logger.debug("list groups for realm {}", StringUtils.trimAllWhitespace(realm)); - return groupManager.getGroups(realm); + return groupManager.searchGroups(realm, q, pageRequest); } @PostMapping("/groups/{realm}") @@ -114,6 +119,7 @@ public Group createGroup( g.setName(name); g.setDescription(description); g.setMembers(reg.getMembers()); + g.setRoles(reg.getRoles()); if (logger.isTraceEnabled()) { logger.trace("group bean: {}", StringUtils.trimAllWhitespace(g.toString())); @@ -164,6 +170,7 @@ public Group updateGroup( g.setName(name); g.setDescription(description); g.setMembers(reg.getMembers()); + g.setRoles(reg.getRoles()); if (logger.isTraceEnabled()) { logger.trace("group bean: {}", StringUtils.trimAllWhitespace(g.toString())); diff --git a/src/main/java/it/smartcommunitylab/aac/groups/GroupManager.java b/src/main/java/it/smartcommunitylab/aac/groups/GroupManager.java index 23023256a..4bf9cb18f 100644 --- a/src/main/java/it/smartcommunitylab/aac/groups/GroupManager.java +++ b/src/main/java/it/smartcommunitylab/aac/groups/GroupManager.java @@ -25,10 +25,15 @@ import it.smartcommunitylab.aac.groups.persistence.GroupEntity; import it.smartcommunitylab.aac.groups.service.GroupService; import it.smartcommunitylab.aac.model.Group; +import it.smartcommunitylab.aac.model.RealmRole; import it.smartcommunitylab.aac.model.Subject; +import it.smartcommunitylab.aac.roles.service.SubjectRoleService; + import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import org.jsoup.Jsoup; import org.jsoup.safety.Safelist; @@ -65,6 +70,10 @@ public class GroupManager { @Autowired private SubjectService subjectService; + + @Autowired + private SubjectRoleService realmRoleService; + /* * Realm groups */ @@ -81,6 +90,9 @@ public Group getGroup(String realm, String groupId, boolean withMembers) throw new IllegalArgumentException("realm mismatch"); } + Set roles = loadGroupRoles(realm, groupId); + g.setRoles(roles); + return g; } @@ -112,6 +124,10 @@ public Group addGroup(String realm, Group g) throws NoSuchRealmException { res.setMembers(new ArrayList<>(members)); } + //add roles if defined + if(g.getRoles() != null) { + realmRoleService.setRoles(groupId, realm, g.getRoles().stream().map(r -> r.getRole()).toList()); + } return res; } @@ -140,6 +156,12 @@ public Group updateGroup(String realm, String groupId, Group g) throws NoSuchRea res.setMembers(new ArrayList<>(members)); } + //update roles if defined + if(g.getRoles() != null) { + Collection roles = realmRoleService.setRoles(groupId, realm, g.getRoles().stream().map(r -> r.getRole()).toList()); + res.setRoles(new HashSet<>(roles)); + } + return res; } @@ -166,6 +188,11 @@ public void deleteGroup(String realm, String groupId) throws NoSuchRealmExceptio } } + @Transactional(readOnly = true) + public Page searchGroups(String realm, String keywords, Pageable pageRequest) throws NoSuchRealmException { + return groupService.searchGroups(realm, keywords, pageRequest); + } + @Transactional(readOnly = true) public Page getGroups(String realm, Pageable pageRequest) throws NoSuchRealmException { return groupService.listGroups(realm, pageRequest); @@ -274,4 +301,13 @@ public Collection setSubjectGroups(String realm, String subject, Collecti public void deleteSubjectFromGroups(String realm, String subject) throws NoSuchSubjectException { groupService.deleteSubjectFromGroups(subject, realm); } + + + /* + * Helpers + */ + + private Set loadGroupRoles(String realm, String groupId) throws NoSuchGroupException { + return new HashSet<>(realmRoleService.getRoles(groupId, realm)); + } } diff --git a/src/main/java/it/smartcommunitylab/aac/groups/persistence/GroupEntity.java b/src/main/java/it/smartcommunitylab/aac/groups/persistence/GroupEntity.java index fe686d41e..27a6b97cc 100644 --- a/src/main/java/it/smartcommunitylab/aac/groups/persistence/GroupEntity.java +++ b/src/main/java/it/smartcommunitylab/aac/groups/persistence/GroupEntity.java @@ -44,8 +44,8 @@ public class GroupEntity { */ @Id @NotNull - @Column(length = 128, unique = true) - private String uuid; + @Column(name = "uuid", length = 128, unique = true) + private String id; @NotNull @Column(length = 128) @@ -75,12 +75,12 @@ public class GroupEntity { @Column(name = "last_modified_date") private Date modifiedDate; - public String getUuid() { - return uuid; + public String getId() { + return id; } - public void setUuid(String uuid) { - this.uuid = uuid; + public void setId(String id) { + this.id = id; } public String getRealm() { diff --git a/src/main/java/it/smartcommunitylab/aac/groups/persistence/GroupEntityRepository.java b/src/main/java/it/smartcommunitylab/aac/groups/persistence/GroupEntityRepository.java index 79c6c5e3f..a4c334349 100644 --- a/src/main/java/it/smartcommunitylab/aac/groups/persistence/GroupEntityRepository.java +++ b/src/main/java/it/smartcommunitylab/aac/groups/persistence/GroupEntityRepository.java @@ -37,4 +37,14 @@ public interface GroupEntityRepository Page findByRealm(String realm, Pageable pageRequest); List findByRealmAndParentGroup(String realm, String parentGroup); + + Page findByRealmAndNameContainingIgnoreCaseOrRealmAndGroupContainingIgnoreCaseOrRealmAndIdContainingIgnoreCase( + String realmn, + String name, + String realmg, + String groupId, + String realmu, + String uuid, + Pageable page + ); } diff --git a/src/main/java/it/smartcommunitylab/aac/groups/service/GroupService.java b/src/main/java/it/smartcommunitylab/aac/groups/service/GroupService.java index 9a88d8f06..0045b43bd 100644 --- a/src/main/java/it/smartcommunitylab/aac/groups/service/GroupService.java +++ b/src/main/java/it/smartcommunitylab/aac/groups/service/GroupService.java @@ -25,6 +25,8 @@ import it.smartcommunitylab.aac.groups.persistence.GroupMemberEntityRepository; import it.smartcommunitylab.aac.model.Group; import it.smartcommunitylab.aac.model.Subject; + +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; @@ -34,6 +36,7 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.support.PageableExecutionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; @@ -108,7 +111,7 @@ public Group addGroup( // create group g = new GroupEntity(); - g.setUuid(s.getSubjectId()); + g.setId(s.getSubjectId()); g.setRealm(realm); g.setGroup(group); g.setParentGroup(parentGroup); @@ -210,6 +213,24 @@ public Collection listGroups(String realm, boolean withMembers) { return groups; } + + @Transactional(readOnly = true) + public Page searchGroups(String realm, String q, Pageable pageRequest) { + List result = new ArrayList<>(); + Page page =StringUtils.hasText(q) + ? groupRepository.findByRealmAndNameContainingIgnoreCaseOrRealmAndGroupContainingIgnoreCaseOrRealmAndIdContainingIgnoreCase(realm, q, realm, q,realm, q, pageRequest) + : groupRepository.findByRealm(realm, pageRequest); + + + page.getContent().forEach(e -> { + long size = groupMemberRepository.countByRealmAndGroup(e.getRealm(), e.getGroup()); + Group g = toGroup(e, size); + result.add(g); + }); + + return PageableExecutionUtils.getPage(result, pageRequest, () -> page.getTotalElements()); + } + @Transactional(readOnly = true) public Page listGroups(String realm, Pageable pageRequest) { return listGroups(realm, pageRequest, false); @@ -361,7 +382,7 @@ public Group renameGroup(String uuid, String realm, String group) throws NoSuchG public void deleteGroup(String realm, String group) { GroupEntity g = groupRepository.findByRealmAndGroup(realm, group); if (g != null) { - deleteGroup(g.getUuid()); + deleteGroup(g.getId()); } } @@ -615,7 +636,7 @@ public void deleteSubjectFromGroups(String subject, String realm) { */ private Group toGroup(GroupEntity ge, Long size) { Group g = new Group(); - g.setGroupId(ge.getUuid()); + g.setGroupId(ge.getId()); g.setRealm(ge.getRealm()); g.setGroup(ge.getGroup()); diff --git a/src/main/java/it/smartcommunitylab/aac/identity/controller/BaseIdentityProviderController.java b/src/main/java/it/smartcommunitylab/aac/identity/controller/BaseIdentityProviderController.java index 598d6f6bc..ac85abc31 100644 --- a/src/main/java/it/smartcommunitylab/aac/identity/controller/BaseIdentityProviderController.java +++ b/src/main/java/it/smartcommunitylab/aac/identity/controller/BaseIdentityProviderController.java @@ -45,6 +45,8 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -112,19 +114,23 @@ public Collection listAuthorities( */ @GetMapping("/idps/{realm}") @Operation(summary = "list identity providers from a given realm") - public Collection listIdps( - @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm + public Page listIdps( + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, + @RequestParam(required = false) String q, + Pageable pageRequest ) throws NoSuchRealmException { logger.debug("list idp for realm {}", StringUtils.trimAllWhitespace(realm)); - return providerManager - .listProviders(realm) + Page page = providerManager + .searchProviders(realm, q, pageRequest); + + page.getContent() .stream() - .map(cp -> { + .forEach(cp -> { cp.setRegistered(providerManager.isProviderRegistered(realm, cp)); - return cp; - }) - .collect(Collectors.toList()); + }); + + return page; } @PostMapping("/idps/{realm}") @@ -218,14 +224,18 @@ public ConfigurableIdentityProvider updateIdp( // check if active ConfigurableIdentityProvider provider = providerManager.getProvider(realm, providerId); - + boolean registered = providerManager.isProviderRegistered(realm, provider); // if force disable provider boolean forceRegistration = force.orElse(false); - if (forceRegistration && providerManager.isProviderRegistered(realm, provider)) { - try { - provider = providerManager.unregisterProvider(realm, providerId); - } catch (NoSuchAuthorityException e) { - // skip + if (registered) { + if(forceRegistration) { + try { + provider = providerManager.unregisterProvider(realm, providerId); + } catch (NoSuchAuthorityException e) { + // skip + } + } else { + throw new IllegalArgumentException("active providers can not be updated, disable or force"); } } diff --git a/src/main/java/it/smartcommunitylab/aac/model/ClientApp.java b/src/main/java/it/smartcommunitylab/aac/model/ClientApp.java index 1cf8cf5f1..8909c6a96 100644 --- a/src/main/java/it/smartcommunitylab/aac/model/ClientApp.java +++ b/src/main/java/it/smartcommunitylab/aac/model/ClientApp.java @@ -94,6 +94,10 @@ public class ClientApp { // @JsonIgnore private Set spaceRoles; + // groups + @JsonProperty("groups") + private Set groups; + // mappers // TODO @@ -292,4 +296,21 @@ public void setSpaceRoles(Collection rr) { this.spaceRoles = new HashSet<>(); spaceRoles.addAll(rr); } + + + /** + * Groups + */ + public Set getGroups() { + return groups; + } + + public void setGroups(Collection gg) { + this.groups = new HashSet<>(); + groups.addAll(gg); + } + + public String getId() { + return this.clientId; + } } diff --git a/src/main/java/it/smartcommunitylab/aac/model/Developer.java b/src/main/java/it/smartcommunitylab/aac/model/Developer.java index a83eefb23..05273a091 100644 --- a/src/main/java/it/smartcommunitylab/aac/model/Developer.java +++ b/src/main/java/it/smartcommunitylab/aac/model/Developer.java @@ -16,14 +16,21 @@ package it.smartcommunitylab.aac.model; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import it.smartcommunitylab.aac.core.auth.RealmGrantedAuthority; + import java.util.Collections; import java.util.Set; + +import javax.validation.Valid; import javax.validation.constraints.NotBlank; -import org.springframework.security.core.GrantedAuthority; +@Valid @JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) public class Developer { @NotBlank @@ -36,7 +43,11 @@ public class Developer { // authorities in AAC // these are either global or realm scoped - private Set authorities; + private Set authorities; + + public Developer() { + this.authorities = Collections.emptySet(); + } public Developer(String subjectId, String realm) { this.subjectId = subjectId; @@ -48,6 +59,10 @@ public String getSubjectId() { return subjectId; } + public String getId() { + return getSubjectId(); + } + public void setSubjectId(String subjectId) { this.subjectId = subjectId; } @@ -76,11 +91,11 @@ public void setEmail(String email) { this.email = email; } - public Set getAuthorities() { + public Set getAuthorities() { return authorities; } - public void setAuthorities(Set authorities) { + public void setAuthorities(Set authorities) { this.authorities = authorities; } diff --git a/src/main/java/it/smartcommunitylab/aac/model/Group.java b/src/main/java/it/smartcommunitylab/aac/model/Group.java index 3466df7ec..6c4b59311 100644 --- a/src/main/java/it/smartcommunitylab/aac/model/Group.java +++ b/src/main/java/it/smartcommunitylab/aac/model/Group.java @@ -69,7 +69,7 @@ public class Group { private Long size; // roles - private Set roles; + private Set roles; @JsonFormat(shape = JsonFormat.Shape.STRING) private Date createDate; @@ -145,11 +145,11 @@ public void setSize(Long size) { this.size = size; } - public Set getRoles() { + public Set getRoles() { return roles; } - public void setRoles(Set roles) { + public void setRoles(Set roles) { this.roles = roles; } @@ -168,6 +168,10 @@ public Date getModifiedDate() { public void setModifiedDate(Date modifiedDate) { this.modifiedDate = modifiedDate; } + + public String getId() { + return this.groupId; + } @Override public String toString() { diff --git a/src/main/java/it/smartcommunitylab/aac/model/Realm.java b/src/main/java/it/smartcommunitylab/aac/model/Realm.java index aa18b556d..a7c0bb331 100644 --- a/src/main/java/it/smartcommunitylab/aac/model/Realm.java +++ b/src/main/java/it/smartcommunitylab/aac/model/Realm.java @@ -16,10 +16,12 @@ package it.smartcommunitylab.aac.model; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import it.smartcommunitylab.aac.oauth.model.OAuth2ConfigurationMap; import it.smartcommunitylab.aac.templates.model.LocalizationConfigurationMap; +import it.smartcommunitylab.aac.templates.model.TemplatesConfigurationMap; import it.smartcommunitylab.aac.tos.TosConfigurationMap; import javax.validation.Valid; import javax.validation.constraints.NotBlank; @@ -27,6 +29,7 @@ @Valid @JsonInclude(Include.ALWAYS) +@JsonIgnoreProperties(ignoreUnknown = true) public class Realm { private String name; @@ -43,11 +46,13 @@ public class Realm { private OAuth2ConfigurationMap oauthConfiguration; private TosConfigurationMap tosConfiguration; private LocalizationConfigurationMap localizationConfiguration; + private TemplatesConfigurationMap templatesConfiguration; public Realm() { this.oauthConfiguration = new OAuth2ConfigurationMap(); this.tosConfiguration = new TosConfigurationMap(); this.localizationConfiguration = new LocalizationConfigurationMap(); + this.templatesConfiguration = new TemplatesConfigurationMap(); } public Realm(String slug) { @@ -55,6 +60,7 @@ public Realm(String slug) { this.oauthConfiguration = new OAuth2ConfigurationMap(); this.tosConfiguration = new TosConfigurationMap(); this.localizationConfiguration = new LocalizationConfigurationMap(); + this.templatesConfiguration = new TemplatesConfigurationMap(); } public String getName() { @@ -73,6 +79,10 @@ public void setEmail(String email) { this.email = email; } + public String getId() { + return getSlug(); + } + public String getSlug() { return slug; } @@ -120,4 +130,20 @@ public LocalizationConfigurationMap getLocalizationConfiguration() { public void setLocalizationConfiguration(LocalizationConfigurationMap localizationConfiguration) { this.localizationConfiguration = localizationConfiguration; } + + public TemplatesConfigurationMap getTemplatesConfiguration() { + return templatesConfiguration; + } + + public void setTemplatesConfiguration(TemplatesConfigurationMap templatesConfiguration) { + this.templatesConfiguration = templatesConfiguration; + } + + public void clearConfig() { + this.oauthConfiguration= null; + this.tosConfiguration= null; + this.localizationConfiguration= null; + this.templatesConfiguration= null; + } + } diff --git a/src/main/java/it/smartcommunitylab/aac/model/RealmRole.java b/src/main/java/it/smartcommunitylab/aac/model/RealmRole.java index 83cf44690..d4162ccd4 100644 --- a/src/main/java/it/smartcommunitylab/aac/model/RealmRole.java +++ b/src/main/java/it/smartcommunitylab/aac/model/RealmRole.java @@ -65,6 +65,10 @@ public String getRoleId() { return roleId; } + public String getId() { + return roleId; + } + public void setRoleId(String roleId) { this.roleId = roleId; } diff --git a/src/main/java/it/smartcommunitylab/aac/model/Subject.java b/src/main/java/it/smartcommunitylab/aac/model/Subject.java index bd58c85f0..ef3902300 100644 --- a/src/main/java/it/smartcommunitylab/aac/model/Subject.java +++ b/src/main/java/it/smartcommunitylab/aac/model/Subject.java @@ -59,6 +59,10 @@ public String getSubjectId() { return subjectId; } + public String getId() { + return getSubjectId(); + } + public String getRealm() { return realm; } diff --git a/src/main/java/it/smartcommunitylab/aac/model/User.java b/src/main/java/it/smartcommunitylab/aac/model/User.java index 896fcdaef..dbe824f32 100644 --- a/src/main/java/it/smartcommunitylab/aac/model/User.java +++ b/src/main/java/it/smartcommunitylab/aac/model/User.java @@ -17,6 +17,7 @@ package it.smartcommunitylab.aac.model; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; @@ -384,9 +385,14 @@ public void setTosAccepted(Boolean tosAccepted) { this.tosAccepted = tosAccepted; } + @JsonGetter("tos") public boolean isTosAccepted() { return tosAccepted != null ? tosAccepted.booleanValue() : false; } + + public String getId() { + return this.subjectId; + } // public void addSpaceRoles(Collection rr) { // if (rr != null) { // spaceRoles.addAll(rr); diff --git a/src/main/java/it/smartcommunitylab/aac/oauth/AACOAuth2AccessToken.java b/src/main/java/it/smartcommunitylab/aac/oauth/AACOAuth2AccessToken.java index 8d2b82316..2ad2c836f 100644 --- a/src/main/java/it/smartcommunitylab/aac/oauth/AACOAuth2AccessToken.java +++ b/src/main/java/it/smartcommunitylab/aac/oauth/AACOAuth2AccessToken.java @@ -62,7 +62,7 @@ public class AACOAuth2AccessToken implements OAuth2AccessToken, Serializable { private Set scope; - private Map additionalInformation = Collections.emptyMap(); + private Map additionalInformation = Collections.emptyMap(); private Date issuedAt; @@ -260,11 +260,11 @@ public void setScope(Set scope) { this.scope = scope; } - public Map getAdditionalInformation() { + public Map getAdditionalInformation() { return additionalInformation; } - public void setAdditionalInformation(Map additionalInformation) { + public void setAdditionalInformation(Map additionalInformation) { this.additionalInformation = additionalInformation; } diff --git a/src/main/java/it/smartcommunitylab/aac/oauth/OAuth2TokenServices.java b/src/main/java/it/smartcommunitylab/aac/oauth/OAuth2TokenServices.java index ac1ed507e..ccb0b8e23 100644 --- a/src/main/java/it/smartcommunitylab/aac/oauth/OAuth2TokenServices.java +++ b/src/main/java/it/smartcommunitylab/aac/oauth/OAuth2TokenServices.java @@ -180,7 +180,7 @@ public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenReque throws AuthenticationException { logger.debug("refresh access token for token " + refreshTokenValue); - OAuth2RefreshToken refreshToken = tokenStore.readRefreshToken(refreshTokenValue); + OAuth2RefreshToken refreshToken = tokenStore.readRefreshTokenForUpdate(refreshTokenValue); if (refreshToken == null) { throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue); } @@ -229,9 +229,9 @@ public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenReque // newly created access tokens // TODO rework with a keyed lock (per client/per user?) to improve performance // also note that AuthorizationEndpoint has a similar approach - AACOAuth2AccessToken accessToken; + // AACOAuth2AccessToken accessToken; - synchronized (this.refreshLock) { + // synchronized (this.refreshLock) { // remove old access tokens, we enforce a single refresh -> accessToken // this way clients will be able to invalidate old tokens by asking refresh // for the same reason we build each time a new accessToken @@ -272,7 +272,7 @@ public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenReque // build a new accessToken logger.debug("create access token for authentication " + refreshedAuthentication.getName()); - accessToken = createAccessToken(refreshedAuthentication, accessValiditySeconds); + AACOAuth2AccessToken accessToken = createAccessToken(refreshedAuthentication, accessValiditySeconds); if (accessToken == null || !StringUtils.hasText(accessToken.getValue())) { throw new OAuth2Exception("token error"); } @@ -302,7 +302,7 @@ public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenReque } tokenStore.storeAccessToken(accessToken, refreshedAuthentication); - } + // } // traceUserLogger.info(String.format("'type':'new','user':'%s','scope':'%s','token':'%s'", // authentication.getName(), String.join(" ", accessToken.getScope()), accessToken.getValue())); diff --git a/src/main/java/it/smartcommunitylab/aac/oauth/auth/ClientRefreshAuthenticationConverter.java b/src/main/java/it/smartcommunitylab/aac/oauth/auth/ClientRefreshAuthenticationConverter.java index 78729c2a2..b3642a8ed 100644 --- a/src/main/java/it/smartcommunitylab/aac/oauth/auth/ClientRefreshAuthenticationConverter.java +++ b/src/main/java/it/smartcommunitylab/aac/oauth/auth/ClientRefreshAuthenticationConverter.java @@ -20,6 +20,8 @@ import it.smartcommunitylab.aac.oauth.model.AuthorizationGrantType; import java.util.Map; import javax.servlet.http.HttpServletRequest; + +import org.springframework.http.HttpHeaders; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2ErrorCodes; @@ -36,16 +38,26 @@ public OAuth2ClientRefreshAuthenticationToken attemptConvert(HttpServletRequest } // fetch and validate parameters + // if client provides a secret we'll skip and prioritize form auth Map parameters = request.getParameterMap(); if ( !parameters.containsKey(OAuth2ParameterNames.CLIENT_ID) || !parameters.containsKey(OAuth2ParameterNames.REFRESH_TOKEN) || - !parameters.containsKey(OAuth2ParameterNames.GRANT_TYPE) + !parameters.containsKey(OAuth2ParameterNames.GRANT_TYPE) || + parameters.containsKey(OAuth2ParameterNames.CLIENT_SECRET) ) { // not a valid request return null; } + // if client provides a auth header we'll skip and prioritize basic auth + if ( + request.getHeader(HttpHeaders.AUTHORIZATION) != null + ) { + // not a valid request + return null; + } + // support refresh flow without secret for public clients // requires refresh token rotation set AuthorizationGrantType grantType = AuthorizationGrantType.parse( diff --git a/src/main/java/it/smartcommunitylab/aac/oauth/common/AACOAuth2AccessTokenSerializer.java b/src/main/java/it/smartcommunitylab/aac/oauth/common/AACOAuth2AccessTokenSerializer.java index 9d854480e..1f898fa5b 100644 --- a/src/main/java/it/smartcommunitylab/aac/oauth/common/AACOAuth2AccessTokenSerializer.java +++ b/src/main/java/it/smartcommunitylab/aac/oauth/common/AACOAuth2AccessTokenSerializer.java @@ -23,6 +23,7 @@ import it.smartcommunitylab.aac.SystemKeys; import it.smartcommunitylab.aac.oauth.AACOAuth2AccessToken; import java.io.IOException; +import java.io.Serializable; import java.util.Collections; import java.util.Date; import java.util.Map; @@ -84,7 +85,7 @@ public void serialize(AACOAuth2AccessToken token, JsonGenerator gen, SerializerP gen.writeStringField(AACOAuth2AccessToken.SCOPE, StringUtils.collectionToDelimitedString(scope, " ")); // add additional fields as presented in map - Map additionalInformation = token.getAdditionalInformation(); + Map additionalInformation = token.getAdditionalInformation(); for (String key : additionalInformation.keySet()) { gen.writeObjectField(key, additionalInformation.get(key)); } diff --git a/src/main/java/it/smartcommunitylab/aac/oauth/model/ClientRegistration.java b/src/main/java/it/smartcommunitylab/aac/oauth/model/ClientRegistration.java index 4aa7592bb..181c18f4e 100644 --- a/src/main/java/it/smartcommunitylab/aac/oauth/model/ClientRegistration.java +++ b/src/main/java/it/smartcommunitylab/aac/oauth/model/ClientRegistration.java @@ -22,10 +22,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import it.smartcommunitylab.aac.repository.ArrayOrStringDeserializer; import it.smartcommunitylab.aac.repository.StringArraySerializer; import java.util.Set; -import org.springframework.security.oauth2.provider.client.Jackson2ArrayOrStringDeserializer; - @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public class ClientRegistration { @@ -46,11 +46,10 @@ public class ClientRegistration { private String name; @JsonProperty("redirect_uris") - @JsonDeserialize(using = Jackson2ArrayOrStringDeserializer.class) private Set redirectUris; @JsonProperty("scope") - @JsonDeserialize(using = Jackson2ArrayOrStringDeserializer.class) + @JsonDeserialize(using = ArrayOrStringDeserializer.class) @JsonSerialize(using = StringArraySerializer.class) private Set scope; diff --git a/src/main/java/it/smartcommunitylab/aac/oauth/model/OAuth2ClientDetails.java b/src/main/java/it/smartcommunitylab/aac/oauth/model/OAuth2ClientDetails.java index 976a5bfa2..ae76e416d 100644 --- a/src/main/java/it/smartcommunitylab/aac/oauth/model/OAuth2ClientDetails.java +++ b/src/main/java/it/smartcommunitylab/aac/oauth/model/OAuth2ClientDetails.java @@ -23,6 +23,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import it.smartcommunitylab.aac.SystemKeys; +import it.smartcommunitylab.aac.repository.ArrayOrStringDeserializer; import it.smartcommunitylab.aac.repository.StringArraySerializer; import java.util.Collection; import java.util.Collections; @@ -31,7 +32,6 @@ import java.util.Set; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.security.oauth2.provider.client.Jackson2ArrayOrStringDeserializer; @JsonInclude(Include.NON_NULL) public class OAuth2ClientDetails implements ClientDetails { @@ -48,12 +48,12 @@ public class OAuth2ClientDetails implements ClientDetails { private String name; @JsonProperty("scope") - @JsonDeserialize(using = Jackson2ArrayOrStringDeserializer.class) + @JsonDeserialize(using = ArrayOrStringDeserializer.class) @JsonSerialize(using = StringArraySerializer.class) private Set scope = Collections.emptySet(); @JsonProperty("resource_ids") - @JsonDeserialize(using = Jackson2ArrayOrStringDeserializer.class) + @JsonDeserialize(using = ArrayOrStringDeserializer.class) @JsonSerialize(using = StringArraySerializer.class) private Set resourceIds = Collections.emptySet(); @@ -61,7 +61,7 @@ public class OAuth2ClientDetails implements ClientDetails { private Set authorizedGrantTypes = Collections.emptySet(); @JsonProperty("token_endpoint_auth_method") - @JsonDeserialize(using = Jackson2ArrayOrStringDeserializer.class) + @JsonDeserialize(using = ArrayOrStringDeserializer.class) @JsonSerialize(using = StringArraySerializer.class) private Set authenticationMethods = Collections.emptySet(); diff --git a/src/main/java/it/smartcommunitylab/aac/oauth/model/OAuth2ConfigurationMap.java b/src/main/java/it/smartcommunitylab/aac/oauth/model/OAuth2ConfigurationMap.java index d28098bb4..8817179b2 100644 --- a/src/main/java/it/smartcommunitylab/aac/oauth/model/OAuth2ConfigurationMap.java +++ b/src/main/java/it/smartcommunitylab/aac/oauth/model/OAuth2ConfigurationMap.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -28,6 +29,7 @@ import javax.validation.Valid; @Valid +@JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public class OAuth2ConfigurationMap implements ConfigurableProperties { diff --git a/src/main/java/it/smartcommunitylab/aac/oauth/service/OAuth2Scheduler.java b/src/main/java/it/smartcommunitylab/aac/oauth/service/OAuth2Scheduler.java new file mode 100644 index 000000000..0ef3270e8 --- /dev/null +++ b/src/main/java/it/smartcommunitylab/aac/oauth/service/OAuth2Scheduler.java @@ -0,0 +1,66 @@ +/* + * Copyright 2024 the original author or authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package it.smartcommunitylab.aac.oauth.service; + +import java.time.Instant; +import java.util.Date; + +import javax.transaction.Transactional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import it.smartcommunitylab.aac.oauth.store.ExtTokenStore; + +@Component +public class OAuth2Scheduler { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + public static final int DEFAULT_DELAY = 24 * 60 * 60 * 1000; //every day + public static final int INITIAL_DELAY = 6 * 1000; //wait 60s for start + + + @Value("${oauth2.accesstoken.cleanup}") + private int accessTokenCleanupInterval; + + @Value("${oauth2.refreshtoken.cleanup}") + private int refreshTokenCleanupInterval; + + @Autowired + private ExtTokenStore tokenStore; + + @Scheduled(fixedDelay = DEFAULT_DELAY, initialDelay = INITIAL_DELAY) + @Transactional + public void deleteExpiredTokens() { + try { + Date now = Date.from(Instant.now()); + + logger.info("remove access tokens expired before {} - {}", now, accessTokenCleanupInterval); + tokenStore.deleteExpiredAccessTokens(accessTokenCleanupInterval); + + logger.info("remove refresh tokens expired before {} - {}", now, refreshTokenCleanupInterval); + tokenStore.deleteExpiredRefreshTokens(refreshTokenCleanupInterval); + } catch (RuntimeException e) { + logger.error("error removing expired tokens", e); + } + } +} diff --git a/src/main/java/it/smartcommunitylab/aac/oauth/store/ExtTokenStore.java b/src/main/java/it/smartcommunitylab/aac/oauth/store/ExtTokenStore.java index 6b29dcc88..9456702ed 100644 --- a/src/main/java/it/smartcommunitylab/aac/oauth/store/ExtTokenStore.java +++ b/src/main/java/it/smartcommunitylab/aac/oauth/store/ExtTokenStore.java @@ -42,9 +42,31 @@ public interface ExtTokenStore extends TokenStore { */ public OAuth2RefreshToken readRefreshTokenForAccessToken(String tokenValue); + /** + * Read refresh token FOR update + * + * @param tokenValue + * @return + */ + public OAuth2RefreshToken readRefreshTokenForUpdate(String token); + + /** * @param clientId the client id to search * @return a collection of access tokens */ Collection findTokensByUserName(String userName); + + + /** + * Delete tokens expired since interval + * @param interval + */ + public void deleteExpiredAccessTokens(long interval); + + /** + * Delete tokens expired since interval + * @param interval + */ + public void deleteExpiredRefreshTokens(long interval); } diff --git a/src/main/java/it/smartcommunitylab/aac/oauth/store/jdbc/AutoJdbcTokenStore.java b/src/main/java/it/smartcommunitylab/aac/oauth/store/jdbc/AutoJdbcTokenStore.java index 813968302..7f886a4ed 100644 --- a/src/main/java/it/smartcommunitylab/aac/oauth/store/jdbc/AutoJdbcTokenStore.java +++ b/src/main/java/it/smartcommunitylab/aac/oauth/store/jdbc/AutoJdbcTokenStore.java @@ -16,19 +16,27 @@ package it.smartcommunitylab.aac.oauth.store.jdbc; +import it.smartcommunitylab.aac.oauth.AACOAuth2AccessToken; import it.smartcommunitylab.aac.oauth.store.ExtTokenStore; import it.smartcommunitylab.aac.oauth.store.ExtendedAuthenticationKeyGenerator; + import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Types; + import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.support.SqlLobValue; +import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2RefreshToken; import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.token.AuthenticationKeyGenerator; +import org.springframework.security.oauth2.provider.token.DefaultAuthenticationKeyGenerator; import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore; /** @@ -44,35 +52,35 @@ public class AutoJdbcTokenStore extends JdbcTokenStore implements ExtTokenStore private JdbcTemplate jdbcTemplate; + private static final String DEFAULT_ACCESS_TOKEN_INSERT_STATEMENT = "insert into oauth_access_token (token_id, token, authentication_id, user_name, client_id, issued_at, expires_at, authentication, refresh_token) values (?, ?, ?, ?, ?, ?, ?, ?, ?)"; private static final String DEFAULT_SELECT_ACCESS_TOKEN_FROM_REFRESH_TOKEN = "select token_id, token from oauth_access_token where refresh_token = ?"; + private static final String DEFAULT_REFRESH_TOKEN_SELECT_STATEMENT = "select token_id, token from oauth_refresh_token where token_id = ? FOR UPDATE"; + private static final String DEFAULT_REFRESH_TOKEN_INSERT_STATEMENT = "insert into oauth_refresh_token (token_id, token, authentication_id, user_name, client_id, issued_at, expires_at, authentication) values (?, ?, ?, ?, ?, ?, ?, ?)"; + private static final String DEFAULT_DELETE_EXPIRED_ACCESS_TOKENS_STATEMENT = "delete from oauth_access_token where expires_at < ?"; + private static final String DEFAULT_DELETE_EXPIRED_REFRESH_TOKENS_STATEMENT = "delete from oauth_refresh_token where expires_at < ?"; + private String insertAccessTokenSql = DEFAULT_ACCESS_TOKEN_INSERT_STATEMENT; private String selectAccessTokenFromRefreshTokenSql = DEFAULT_SELECT_ACCESS_TOKEN_FROM_REFRESH_TOKEN; + private String deleteExpiredAccessTokenSql = DEFAULT_DELETE_EXPIRED_ACCESS_TOKENS_STATEMENT; + + private String insertRefreshTokenSql = DEFAULT_REFRESH_TOKEN_INSERT_STATEMENT; + private String selectRefreshTokenSql = DEFAULT_REFRESH_TOKEN_SELECT_STATEMENT; + private String deleteExpiredRefreshTokenSql = DEFAULT_DELETE_EXPIRED_REFRESH_TOKENS_STATEMENT; + + private AuthenticationKeyGenerator authenticationKeyGenerator = new DefaultAuthenticationKeyGenerator(); + - /** - * @param dataSource - */ public AutoJdbcTokenStore(DataSource dataSource) { super(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource); // set a saner authkey generator, but we should really just drop it, we won't // read back anyway - this.setAuthenticationKeyGenerator(new ExtendedAuthenticationKeyGenerator()); + this.authenticationKeyGenerator = new ExtendedAuthenticationKeyGenerator(); + super.setAuthenticationKeyGenerator(this.authenticationKeyGenerator ); } - // /** - // * @param dataSource - // * @param createRefreshTokenStatement - // * @param createAccessTokenStatement - // */ - // public AutoJdbcTokenStore(DataSource dataSource, String createRefreshTokenStatement, - // String createAccessTokenStatement) { - // super(dataSource); - // this.createRefreshTokenStatement = createRefreshTokenStatement; - // this.createAccessTokenStatement = createAccessTokenStatement; - // initSchema(dataSource); - // } @Override public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) { @@ -117,4 +125,88 @@ public OAuth2RefreshToken readRefreshTokenForAccessToken(String tokenValue) { return accessToken.getRefreshToken(); } + + public OAuth2RefreshToken readRefreshTokenForUpdate(String token) { + OAuth2RefreshToken refreshToken = null; + + try { + refreshToken = jdbcTemplate.queryForObject(selectRefreshTokenSql, new RowMapper() { + public OAuth2RefreshToken mapRow(ResultSet rs, int rowNum) throws SQLException { + return deserializeRefreshToken(rs.getBytes(2)); + } + }, extractTokenKey(token)); + } catch (EmptyResultDataAccessException e) { + } catch (IllegalArgumentException e) { + removeRefreshToken(token); + } + + return refreshToken; + } + + + @Override + public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) { + String refreshToken = null; + if (token.getRefreshToken() != null) { + refreshToken = token.getRefreshToken().getValue(); + } + + java.sql.Timestamp expiresAt = null; + if(token.getExpiration() != null) { + expiresAt = new java.sql.Timestamp(token.getExpiration().getTime()); + } + + java.sql.Timestamp issuedAt = new java.sql.Timestamp(System.currentTimeMillis()); + if(token instanceof AACOAuth2AccessToken && ((AACOAuth2AccessToken)token).getIssuedAt() != null) { + issuedAt = new java.sql.Timestamp(((AACOAuth2AccessToken)token).getIssuedAt().getTime()); + } + + //DISABLED: store should store *new* tokens, not update! + // if (readAccessToken(token.getValue())!=null) { + // removeAccessToken(token.getValue()); + // } + + jdbcTemplate.update(insertAccessTokenSql, new Object[] { extractTokenKey(token.getValue()), + new SqlLobValue(serializeAccessToken(token)), authenticationKeyGenerator.extractKey(authentication), + authentication.isClientOnly() ? null : authentication.getName(), + authentication.getOAuth2Request().getClientId(), + issuedAt, expiresAt, + new SqlLobValue(serializeAuthentication(authentication)), extractTokenKey(refreshToken) }, new int[] { + Types.VARCHAR, Types.BLOB, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP, Types.TIMESTAMP, Types.BLOB, Types.VARCHAR }); + } + + @Override + public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) { + java.sql.Timestamp expiresAt = null; + if(refreshToken instanceof ExpiringOAuth2RefreshToken && ((ExpiringOAuth2RefreshToken)refreshToken).getExpiration() != null) { + expiresAt = new java.sql.Timestamp(((ExpiringOAuth2RefreshToken)refreshToken).getExpiration().getTime()); + } + + jdbcTemplate.update(insertRefreshTokenSql, new Object[] { extractTokenKey(refreshToken.getValue()), + new SqlLobValue(serializeRefreshToken(refreshToken)),authenticationKeyGenerator.extractKey(authentication), + authentication.isClientOnly() ? null : authentication.getName(), + authentication.getOAuth2Request().getClientId(), + new java.sql.Timestamp(System.currentTimeMillis()), expiresAt, + new SqlLobValue(serializeAuthentication(authentication)) }, new int[] { + Types.VARCHAR, Types.BLOB, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP, Types.TIMESTAMP, Types.BLOB }); + } + + + @Override + public void deleteExpiredAccessTokens(long interval) { + //interval in seconds + long timestamp = System.currentTimeMillis()- (interval*1000); + + jdbcTemplate.update(deleteExpiredAccessTokenSql, new Object[] {new java.sql.Timestamp(timestamp)}, new int[] {Types.TIMESTAMP}); + } + + + @Override + public void deleteExpiredRefreshTokens(long interval) { + //interval in seconds + long timestamp = System.currentTimeMillis()- (interval*1000); + + jdbcTemplate.update(deleteExpiredRefreshTokenSql, new Object[] {new java.sql.Timestamp(timestamp)}, new int[] {Types.TIMESTAMP}); + } + } diff --git a/src/main/java/it/smartcommunitylab/aac/openidfed/auth/OpenIdFedResolverFilter.java b/src/main/java/it/smartcommunitylab/aac/openidfed/auth/OpenIdFedResolverFilter.java index 71e138663..7f917a849 100644 --- a/src/main/java/it/smartcommunitylab/aac/openidfed/auth/OpenIdFedResolverFilter.java +++ b/src/main/java/it/smartcommunitylab/aac/openidfed/auth/OpenIdFedResolverFilter.java @@ -135,7 +135,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse if (!StringUtils.hasText(anchor) || !StringUtils.hasText(sub)) { OAuth2Error oauth2Error = new OAuth2Error( OAuth2ErrorCodes.INVALID_REQUEST, - "Missing required parameters [sub] or [trust_anchor]", + "Missing required parameters [sub] or [anchor]", null ); throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); @@ -258,7 +258,7 @@ private String writeMetadata( trustMarks.stream().map(t -> t.toJSONObject()).collect(Collectors.toList()) ); } - + //add trust chain if (trustChain != null) { claims.claim("trust_chain", trustChain.toSerializedJWTs()); diff --git a/src/main/java/it/smartcommunitylab/aac/openidfed/provider/OpenIdFedIdentityProviderConfig.java b/src/main/java/it/smartcommunitylab/aac/openidfed/provider/OpenIdFedIdentityProviderConfig.java index c13b85beb..cd4425254 100644 --- a/src/main/java/it/smartcommunitylab/aac/openidfed/provider/OpenIdFedIdentityProviderConfig.java +++ b/src/main/java/it/smartcommunitylab/aac/openidfed/provider/OpenIdFedIdentityProviderConfig.java @@ -104,7 +104,7 @@ public OpenIdProviderDiscoveryService getProviderService() { Set providers = configMap .getProviders() .stream() - .map(p -> p.getValue()) + // .map(p -> p.getValue()) .collect(Collectors.toSet()); providerService = new StaticOpenIdProviderDiscoveryService( diff --git a/src/main/java/it/smartcommunitylab/aac/openidfed/provider/OpenIdFedIdentityProviderConfigMap.java b/src/main/java/it/smartcommunitylab/aac/openidfed/provider/OpenIdFedIdentityProviderConfigMap.java index 80a892b6d..949ce33b3 100644 --- a/src/main/java/it/smartcommunitylab/aac/openidfed/provider/OpenIdFedIdentityProviderConfigMap.java +++ b/src/main/java/it/smartcommunitylab/aac/openidfed/provider/OpenIdFedIdentityProviderConfigMap.java @@ -68,7 +68,7 @@ public class OpenIdFedIdentityProviderConfigMap extends AbstractConfigMap { // openid-fed private String trustAnchor; - private Set providers; + private Set providers; private String federationJwks; private Set acrValues; @@ -179,11 +179,11 @@ public void setTrustAnchor(String trustAnchor) { this.trustAnchor = trustAnchor; } - public Set getProviders() { + public Set getProviders() { return providers; } - public void setProviders(Set providers) { + public void setProviders(Set providers) { this.providers = providers; } diff --git a/src/main/java/it/smartcommunitylab/aac/realms/RealmManager.java b/src/main/java/it/smartcommunitylab/aac/realms/RealmManager.java index f808e5254..3a27a3819 100644 --- a/src/main/java/it/smartcommunitylab/aac/realms/RealmManager.java +++ b/src/main/java/it/smartcommunitylab/aac/realms/RealmManager.java @@ -76,14 +76,14 @@ import javax.validation.Valid; import javax.validation.constraints.NotBlank; import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.safety.Cleaner; import org.jsoup.safety.Safelist; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; @@ -245,6 +245,28 @@ public Realm updateRealm(String slug, Realm r) throws NoSuchRealmException, Regi localizationConfigMap = r.getLocalizationConfiguration().getConfiguration(); } + Map templatesConfigMap = null; + if (r.getTemplatesConfiguration() != null) { + // validate style + // TODO add css validator + String customStyle = r.getTemplatesConfiguration().getCustomStyle(); + if (customStyle == null || "null".equals(customStyle)) { + customStyle = ""; + } + // use wholetext to avoid escaping ><& etc. + // this could break the final document + // TODO use a proper CSS parser + Document dirty = Jsoup.parseBodyFragment(customStyle); + Cleaner cleaner = new Cleaner(Safelist.none()); + Document clean = cleaner.clean(dirty); + + String style = clean.body().wholeText(); + r.getTemplatesConfiguration().setCustomStyle(style); + + //export + templatesConfigMap = r.getTemplatesConfiguration().getConfiguration(); + } + Realm realm = realmService.updateRealm( slug, name, @@ -253,7 +275,8 @@ public Realm updateRealm(String slug, Realm r) throws NoSuchRealmException, Regi r.isPublic(), oauth2ConfigMap, tosConfigMap, - localizationConfigMap + localizationConfigMap, + templatesConfigMap ); return realm; @@ -526,24 +549,22 @@ public void removeDeveloper(String realm, String subjectId) throws NoSuchRealmEx } private Developer toDeveloper(String realm, User user) { - Developer dev = new Developer(user.getSubjectId(), realm); + Developer dev = new Developer(user.getSubjectId(), user.getRealm()); dev.setUsername(user.getUsername()); dev.setEmail(user.getEmail()); // filter realm+global authorities - Set authorities = user + Set authorities = user .getAuthorities() .stream() - .filter(a -> { - if (a instanceof SimpleGrantedAuthority) { - return true; - } + .filter(a -> { if (a instanceof RealmGrantedAuthority) { return realm.equals(((RealmGrantedAuthority) a).getRealm()); } return false; }) + .map(r -> (RealmGrantedAuthority)r) .collect(Collectors.toSet()); dev.setAuthorities(authorities); diff --git a/src/main/java/it/smartcommunitylab/aac/realms/persistence/RealmEntity.java b/src/main/java/it/smartcommunitylab/aac/realms/persistence/RealmEntity.java index 0a249ba83..a1da7822c 100644 --- a/src/main/java/it/smartcommunitylab/aac/realms/persistence/RealmEntity.java +++ b/src/main/java/it/smartcommunitylab/aac/realms/persistence/RealmEntity.java @@ -82,6 +82,12 @@ public class RealmEntity { @Convert(converter = HashMapConverter.class) private Map localizationConfigurationMap; + // TODO move to templatesConfigProvider + @Lob + @Column(name = "templates_configuration_map") + @Convert(converter = HashMapConverter.class) + private Map templatesConfigurationMap; + public String getName() { return name; } @@ -161,4 +167,13 @@ public Map getLocalizationConfigurationMap() { public void setLocalizationConfigurationMap(Map localizationConfigurationMap) { this.localizationConfigurationMap = localizationConfigurationMap; } + + public Map getTemplatesConfigurationMap() { + return templatesConfigurationMap; + } + + public void setTemplatesConfigurationMap(Map templatesConfigurationMap) { + this.templatesConfigurationMap = templatesConfigurationMap; + } + } diff --git a/src/main/java/it/smartcommunitylab/aac/realms/service/RealmService.java b/src/main/java/it/smartcommunitylab/aac/realms/service/RealmService.java index 4fa82fda7..7796465f5 100644 --- a/src/main/java/it/smartcommunitylab/aac/realms/service/RealmService.java +++ b/src/main/java/it/smartcommunitylab/aac/realms/service/RealmService.java @@ -26,6 +26,7 @@ import it.smartcommunitylab.aac.realms.persistence.RealmEntity; import it.smartcommunitylab.aac.realms.persistence.RealmEntityRepository; import it.smartcommunitylab.aac.templates.model.LocalizationConfigurationMap; +import it.smartcommunitylab.aac.templates.model.TemplatesConfigurationMap; import it.smartcommunitylab.aac.tos.TosConfigurationMap; import java.io.Serializable; import java.util.HashSet; @@ -158,7 +159,8 @@ public Realm updateRealm( boolean isPublic, Map oauthConfigurationMap, Map tosConfigurationMap, - Map locConfigurationMap + Map locConfigurationMap, + Map templatesConfigurationMap ) throws NoSuchRealmException { if (SystemKeys.REALM_GLOBAL.equals(slug) || SystemKeys.REALM_SYSTEM.equals(slug)) { throw new IllegalArgumentException("system realms are immutable"); @@ -177,6 +179,7 @@ public Realm updateRealm( r.setOAuthConfigurationMap(oauthConfigurationMap); r.setTosConfigurationMap(tosConfigurationMap); r.setLocalizationConfigurationMap(locConfigurationMap); + r.setTemplatesConfigurationMap(templatesConfigurationMap); r = realmRepository.save(r); @@ -275,6 +278,12 @@ private Realm toRealm(RealmEntity re) { } r.setLocalizationConfiguration(locConfigMap); + TemplatesConfigurationMap templatesConfigMap = new TemplatesConfigurationMap(); + if (re.getTemplatesConfigurationMap() != null) { + templatesConfigMap.setConfiguration(re.getTemplatesConfigurationMap()); + } + r.setTemplatesConfiguration(templatesConfigMap); + return r; } } diff --git a/src/main/java/it/smartcommunitylab/aac/repository/ArrayOrStringDeserializer.java b/src/main/java/it/smartcommunitylab/aac/repository/ArrayOrStringDeserializer.java new file mode 100644 index 000000000..425398b11 --- /dev/null +++ b/src/main/java/it/smartcommunitylab/aac/repository/ArrayOrStringDeserializer.java @@ -0,0 +1,41 @@ +package it.smartcommunitylab.aac.repository; + +import java.io.IOException; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.springframework.util.StringUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.type.SimpleType; + + +public class ArrayOrStringDeserializer extends StdDeserializer> { + + public ArrayOrStringDeserializer() { + super(Set.class); + } + + @Override + public Set deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + JsonToken token = jp.getCurrentToken(); + if (token.isScalarValue()) { + //use regex and comma separated to handle incorrectly formatted space separated + String list = jp.getText().replaceAll("\\s+", ","); + return StringUtils.commaDelimitedListToSet(list); + } else { + return jp.readValueAs(new TypeReference>() {}); + } + } + + @Override + public JavaType getValueType() { + return SimpleType.construct(String.class); + } +} \ No newline at end of file diff --git a/src/main/java/it/smartcommunitylab/aac/roles/BaseRealmRolesController.java b/src/main/java/it/smartcommunitylab/aac/roles/BaseRealmRolesController.java index d6efe9a81..5883f1083 100644 --- a/src/main/java/it/smartcommunitylab/aac/roles/BaseRealmRolesController.java +++ b/src/main/java/it/smartcommunitylab/aac/roles/BaseRealmRolesController.java @@ -35,6 +35,8 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.oauth2.provider.approval.Approval; import org.springframework.util.Assert; @@ -78,12 +80,14 @@ public String getAuthority() { @GetMapping("/roles/{realm}") @Operation(summary = "list roles for realm") - public Collection getRealmRoles( - @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm + public Page getRealmRoles( + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, + @RequestParam(required = false) String q, + Pageable pageRequest ) throws NoSuchRealmException { logger.debug("list roles for realm {}", StringUtils.trimAllWhitespace(realm)); - return roleManager.getRealmRoles(realm); + return roleManager.searchRoles(realm, q, pageRequest); } @PostMapping("/roles/{realm}") @@ -104,6 +108,8 @@ public RealmRole createRealmRole( r.setRole(role); r.setName(name); r.setDescription(description); + r.setSubjects(reg.getSubjects()); + r.setPermissions(reg.getPermissions()); if (logger.isTraceEnabled()) { logger.trace("role bean: {}", StringUtils.trimAllWhitespace(r.toString())); @@ -154,7 +160,9 @@ public RealmRole updateRealmRole( r.setRole(role); r.setName(name); r.setDescription(description); - + r.setSubjects(reg.getSubjects()); + r.setPermissions(reg.getPermissions()); + if (logger.isTraceEnabled()) { logger.trace("role bean: {}", StringUtils.trimAllWhitespace(r.toString())); } diff --git a/src/main/java/it/smartcommunitylab/aac/roles/RealmRoleManager.java b/src/main/java/it/smartcommunitylab/aac/roles/RealmRoleManager.java index fe4219c1b..bb873f731 100644 --- a/src/main/java/it/smartcommunitylab/aac/roles/RealmRoleManager.java +++ b/src/main/java/it/smartcommunitylab/aac/roles/RealmRoleManager.java @@ -43,6 +43,8 @@ import org.jsoup.Jsoup; import org.jsoup.safety.Safelist; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; @@ -84,6 +86,9 @@ public class RealmRoleManager { /* * Realm roles */ + public Page searchRoles(String realm, String keywords, Pageable pageRequest) throws NoSuchRealmException { + return rolesService.searchRoles(realm, keywords, pageRequest); + } public Collection getRealmRoles(String realm) { return rolesService.listRoles(realm); diff --git a/src/main/java/it/smartcommunitylab/aac/roles/persistence/RealmRoleEntityRepository.java b/src/main/java/it/smartcommunitylab/aac/roles/persistence/RealmRoleEntityRepository.java index dffbe0aec..eec547bde 100644 --- a/src/main/java/it/smartcommunitylab/aac/roles/persistence/RealmRoleEntityRepository.java +++ b/src/main/java/it/smartcommunitylab/aac/roles/persistence/RealmRoleEntityRepository.java @@ -18,6 +18,9 @@ import it.smartcommunitylab.aac.repository.CustomJpaRepository; import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; @Repository @@ -25,4 +28,16 @@ public interface RealmRoleEntityRepository extends CustomJpaRepository findByRealm(String realm); + Page findByRealm(String realm, Pageable pageRequest); + + + Page findByRealmAndNameContainingIgnoreCaseOrRealmAndRoleContainingIgnoreCaseOrRealmAndIdContainingIgnoreCase( + String realmn, + String name, + String realmg, + String role, + String realmu, + String id, + Pageable page + ); } diff --git a/src/main/java/it/smartcommunitylab/aac/roles/scopes/RolesScopeProvider.java b/src/main/java/it/smartcommunitylab/aac/roles/scopes/RolesScopeProvider.java index 158a9c475..afad468a3 100644 --- a/src/main/java/it/smartcommunitylab/aac/roles/scopes/RolesScopeProvider.java +++ b/src/main/java/it/smartcommunitylab/aac/roles/scopes/RolesScopeProvider.java @@ -72,4 +72,8 @@ public Collection getScopes() { public ScopeApprover getApprover(String scope) { return approvers.get(scope); } + + public String getId() { + return this.getResourceId(); + } } diff --git a/src/main/java/it/smartcommunitylab/aac/roles/service/RealmRoleService.java b/src/main/java/it/smartcommunitylab/aac/roles/service/RealmRoleService.java index 50d8e748c..fb911acb0 100644 --- a/src/main/java/it/smartcommunitylab/aac/roles/service/RealmRoleService.java +++ b/src/main/java/it/smartcommunitylab/aac/roles/service/RealmRoleService.java @@ -27,11 +27,16 @@ import it.smartcommunitylab.aac.roles.persistence.RealmRoleEntityRepository; import it.smartcommunitylab.aac.roles.persistence.SubjectRoleEntity; import it.smartcommunitylab.aac.roles.persistence.SubjectRoleEntityRepository; + +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.support.PageableExecutionUtils; import org.springframework.security.oauth2.provider.approval.Approval; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -166,6 +171,24 @@ public RealmRole getRole(String realm, String role, boolean withSubjects) throws return rr; } + + @Transactional(readOnly = true) + public Page searchRoles(String realm, String q, Pageable pageRequest) { + List result = new ArrayList<>(); + Page page =StringUtils.hasText(q) + ? roleRepository.findByRealmAndNameContainingIgnoreCaseOrRealmAndRoleContainingIgnoreCaseOrRealmAndIdContainingIgnoreCase(realm, q, realm, q,realm, q, pageRequest) + : roleRepository.findByRealm(realm, pageRequest); + + + page.getContent().forEach(e -> { + long size = rolesRepository.countByRealmAndRole(e.getRealm(), e.getRole()); + RealmRole g = toRole(e, size); + result.add(g); + }); + + return PageableExecutionUtils.getPage(result, pageRequest, () -> page.getTotalElements()); + } + @Transactional(readOnly = true) public Collection listRoles(String realm) { return roleRepository.findByRealm(realm).stream().map(r -> toRole(r)).collect(Collectors.toList()); diff --git a/src/main/java/it/smartcommunitylab/aac/roles/service/SubjectRoleService.java b/src/main/java/it/smartcommunitylab/aac/roles/service/SubjectRoleService.java index 0dba70816..f0ac5bd3d 100644 --- a/src/main/java/it/smartcommunitylab/aac/roles/service/SubjectRoleService.java +++ b/src/main/java/it/smartcommunitylab/aac/roles/service/SubjectRoleService.java @@ -17,6 +17,7 @@ package it.smartcommunitylab.aac.roles.service; import it.smartcommunitylab.aac.model.RealmRole; +import it.smartcommunitylab.aac.roles.persistence.RealmRoleEntity; import it.smartcommunitylab.aac.roles.persistence.RealmRoleEntityRepository; import it.smartcommunitylab.aac.roles.persistence.SubjectRoleEntity; import it.smartcommunitylab.aac.roles.persistence.SubjectRoleEntityRepository; @@ -255,9 +256,16 @@ public void deleteRoles(String subjectId, String realm) { } private RealmRole toRole(SubjectRoleEntity r) { - RealmRole role = new RealmRole(r.getRealm(), r.getRole()); - // TODO evaluate loading role model to fill properties - + RealmRole role = new RealmRole(r.getRealm(), r.getRole()); + // load role model to fill properties + RealmRoleEntity re = roleRepository.findByRealmAndRole(r.getRealm(), r.getRole()); + if (re != null) { + role.setRoleId(re.getId()); + String name = re.getName() != null ? re.getName() : re.getRole(); + role.setName(name); + role.setDescription(re.getDescription()); + } + return role; } } diff --git a/src/main/java/it/smartcommunitylab/aac/scope/Resource.java b/src/main/java/it/smartcommunitylab/aac/scope/Resource.java index e29fe832c..ec3d199a4 100644 --- a/src/main/java/it/smartcommunitylab/aac/scope/Resource.java +++ b/src/main/java/it/smartcommunitylab/aac/scope/Resource.java @@ -25,7 +25,13 @@ import javax.validation.constraints.Pattern; import org.springframework.util.Assert; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + @Valid +@JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) public class Resource { @Pattern(regexp = SystemKeys.SLUG_PATTERN) @@ -86,6 +92,10 @@ public void setScopes(Collection scopes) { this.scopes = new HashSet<>(); this.scopes.addAll(scopes); } + + public String getId() { + return getResourceId(); + } @Override public int hashCode() { diff --git a/src/main/java/it/smartcommunitylab/aac/scope/Scope.java b/src/main/java/it/smartcommunitylab/aac/scope/Scope.java index f45d40602..76666414b 100644 --- a/src/main/java/it/smartcommunitylab/aac/scope/Scope.java +++ b/src/main/java/it/smartcommunitylab/aac/scope/Scope.java @@ -24,7 +24,13 @@ import javax.validation.constraints.Pattern; import org.springframework.util.Assert; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + @Valid +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(Include.NON_NULL) public class Scope { @Pattern(regexp = SystemKeys.SCOPE_PATTERN) @@ -48,12 +54,12 @@ public Scope(String scope) { } public String getId() { - return scope; + return getScope(); } - public void setId(String id) { - this.scope = id; - } + // public void setId(String id) { + // this.scope = id; + // } public String getScope() { return scope; diff --git a/src/main/java/it/smartcommunitylab/aac/scope/controller/BaseScopesController.java b/src/main/java/it/smartcommunitylab/aac/scope/controller/BaseScopesController.java index eeafdd629..3a49c0f35 100644 --- a/src/main/java/it/smartcommunitylab/aac/scope/controller/BaseScopesController.java +++ b/src/main/java/it/smartcommunitylab/aac/scope/controller/BaseScopesController.java @@ -38,6 +38,7 @@ import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; /* * Base controller for scopes @@ -67,9 +68,14 @@ public String getAuthority() { @GetMapping("/scopes/{realm}") @Operation(summary = "Get scopes for the given realm") public Collection listScopes( - @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, + @RequestParam(required = false) String q ) throws NoSuchRealmException { logger.debug("list scopes"); + if(q != null) { + return scopeManager.listScopes().stream().filter(s -> s.getScope().toLowerCase().contains(q.toLowerCase())).toList(); + } + return scopeManager.listScopes(); } @@ -87,18 +93,25 @@ public Scope getScope( @GetMapping("/resources/{realm}") @Operation(summary = "List resources for the given realm") public Collection listResources( - @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, + @RequestParam(required = false) String q ) throws NoSuchRealmException { logger.debug("list resources"); - - return scopeManager.listResources(); + if(q == null) { + return scopeManager.listResources(); + } else { + //filter locally + return scopeManager.listResources().stream().filter(r -> { + return r.getName().toLowerCase().contains(q.toLowerCase()) || r.getResourceId().toLowerCase().contains(q.toLowerCase()); + }).toList(); + } } @GetMapping("/resources/{realm}/{resourceId}") @Operation(summary = "Get a resource with all its scopes for the given realm") - public Resource listResources( + public Resource getResource( @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, - @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String resourceId + @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.URI_PATTERN) String resourceId ) throws NoSuchRealmException, NoSuchResourceException { logger.debug("get resource {}", StringUtils.trimAllWhitespace(resourceId)); diff --git a/src/main/java/it/smartcommunitylab/aac/services/Service.java b/src/main/java/it/smartcommunitylab/aac/services/Service.java index 6ce75adb8..e922cf703 100644 --- a/src/main/java/it/smartcommunitylab/aac/services/Service.java +++ b/src/main/java/it/smartcommunitylab/aac/services/Service.java @@ -126,6 +126,10 @@ public Collection getClaims() { public void setClaims(Collection claims) { this.claims = claims; } + + public String getId() { + return this.serviceId; + } @JsonProperty("claimMapping") public Map getClaimMappingBase64() { diff --git a/src/main/java/it/smartcommunitylab/aac/services/ServiceClaim.java b/src/main/java/it/smartcommunitylab/aac/services/ServiceClaim.java index 0cc6b462f..e42307505 100644 --- a/src/main/java/it/smartcommunitylab/aac/services/ServiceClaim.java +++ b/src/main/java/it/smartcommunitylab/aac/services/ServiceClaim.java @@ -47,6 +47,10 @@ public class ServiceClaim extends AbstractClaim { private boolean multiple = false; + public String getId() { + return getKey(); + } + public String getServiceId() { return serviceId; } diff --git a/src/main/java/it/smartcommunitylab/aac/spid/provider/SpidIdentityProviderConfig.java b/src/main/java/it/smartcommunitylab/aac/spid/provider/SpidIdentityProviderConfig.java index 3a87201e7..3b87244c1 100644 --- a/src/main/java/it/smartcommunitylab/aac/spid/provider/SpidIdentityProviderConfig.java +++ b/src/main/java/it/smartcommunitylab/aac/spid/provider/SpidIdentityProviderConfig.java @@ -40,8 +40,6 @@ import org.opensaml.security.credential.Credential; import org.opensaml.security.credential.CredentialSupport; import org.opensaml.security.credential.UsageType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.security.saml2.Saml2Exception; import org.springframework.security.saml2.core.Saml2X509Credential; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; @@ -56,8 +54,6 @@ public class SpidIdentityProviderConfig extends AbstractIdentityProviderConfig toRelyingPartyRegistrations() throws IOExc registrations.add(toRelyingPartyRegistration(idpMetadataUrl)); } catch (Saml2Exception | ConnectException e) { // skip that registration if that idp is offline - logger.warn("error building registration for {} due to error {} ", idpMetadataUrl, e.getMessage()); } } } catch (URISyntaxException e) { diff --git a/src/main/java/it/smartcommunitylab/aac/spid/provider/SpidIdentityProviderConfigMap.java b/src/main/java/it/smartcommunitylab/aac/spid/provider/SpidIdentityProviderConfigMap.java index 77e745105..94fe89fd0 100644 --- a/src/main/java/it/smartcommunitylab/aac/spid/provider/SpidIdentityProviderConfigMap.java +++ b/src/main/java/it/smartcommunitylab/aac/spid/provider/SpidIdentityProviderConfigMap.java @@ -50,34 +50,26 @@ public class SpidIdentityProviderConfigMap extends AbstractConfigMap implements private String entityId; // options - @NotBlank private String signingKey; - @NotBlank private String signingCertificate; // for // options (suggested but not mandatory) - @NotBlank private String organizationDisplayName; - @NotBlank private String organizationName; - @NotBlank private String organizationUrl; // options, only public SP is currently supported - @NotBlank @Pattern(regexp = SystemKeys.EMAIL_PATTERN) private String contactPerson_EmailAddress; - @NotBlank @Pattern(regexp = "^[A-Za-z0-9_]*$") private String contactPerson_IPACode; private Boolean contactPerson_Public; // Public/Private - @Pattern(regexp = "^other|billing$") private String contactPerson_Type; // "other" (mandatory), optionally includes "billing" (unless private SP, in which case "billing" is also mandatory) // AAC options @@ -88,7 +80,6 @@ public class SpidIdentityProviderConfigMap extends AbstractConfigMap implements private String idpMetadataUrl; // optional (see note above) private Set spidAttributes; // optional - @NotNull private SpidAuthnContext authnContext; private SpidUserAttribute subAttributeName; // optional diff --git a/src/main/java/it/smartcommunitylab/aac/templates/LanguageHandlerInterceptor.java b/src/main/java/it/smartcommunitylab/aac/templates/LanguageHandlerInterceptor.java index b2b4e92f7..3a324a575 100644 --- a/src/main/java/it/smartcommunitylab/aac/templates/LanguageHandlerInterceptor.java +++ b/src/main/java/it/smartcommunitylab/aac/templates/LanguageHandlerInterceptor.java @@ -17,17 +17,16 @@ package it.smartcommunitylab.aac.templates; import it.smartcommunitylab.aac.SystemKeys; -import it.smartcommunitylab.aac.common.NoSuchProviderException; import it.smartcommunitylab.aac.internal.templates.InternalRegisterAccountTemplate; +import it.smartcommunitylab.aac.model.Realm; +import it.smartcommunitylab.aac.realms.service.RealmService; import it.smartcommunitylab.aac.templates.model.LoginTemplate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -36,13 +35,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.stereotype.Component; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder; @Component @@ -60,6 +56,10 @@ public class LanguageHandlerInterceptor implements HandlerInterceptor { WHITELIST_VIEWS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(WHITELIST_VIEWS_VALUES))); } + @Autowired + private RealmService realmService; + + @Autowired private TemplateAuthority templateAuthority; @@ -99,7 +99,7 @@ public void postHandle( // realm Object slug = modelAndView.getModel().get("realm"); if (slug != null && slug instanceof String) { - String realm = (String) slug; + Realm realm = realmService.getRealm((String) slug); Locale locale = LocaleContextHolder.getLocale(); String language = locale.getLanguage(); @@ -110,13 +110,18 @@ public void postHandle( builder.query(request.getQueryString()); List languages = new ArrayList<>(); - try { - // load realm languages - templateAuthority - .getProviderByRealm(realm) - .getLanguages() + // try { + // load realm languages from templates + //DEPRECATED + // templateAuthority + // .getProviderByRealm(realm) + // .getLanguages() + + //load realm languages from config + if(realm.getLocalizationConfiguration() != null && realm.getLocalizationConfiguration().getLanguages() != null) { + realm.getLocalizationConfiguration().getLanguages() .forEach(l -> { - Locale loc = StringUtils.parseLocale(l); + Locale loc = StringUtils.parseLocale(l.getValue()); if (loc == null) { return; } @@ -126,15 +131,16 @@ public void postHandle( String url = builder.build().toString(); String label = loc.getDisplayLanguage(locale); LanguageValue lv = new LanguageValue(); - lv.setCode(l); + lv.setCode(l.getValue()); lv.setLabel(label); lv.setUrl(url); languages.add(lv); }); - } catch (NoSuchProviderException e) { - // skip on error - } + } + // } catch (NoSuchProviderException e) { + // // skip on error + // } modelAndView.addObject("languages", languages); diff --git a/src/main/java/it/smartcommunitylab/aac/templates/TemplateHandlerInterceptor.java b/src/main/java/it/smartcommunitylab/aac/templates/TemplateHandlerInterceptor.java index 0833aa83e..527f95548 100644 --- a/src/main/java/it/smartcommunitylab/aac/templates/TemplateHandlerInterceptor.java +++ b/src/main/java/it/smartcommunitylab/aac/templates/TemplateHandlerInterceptor.java @@ -141,12 +141,17 @@ public void postHandle( .getProviderByRealm(realm) .getTemplate(name, locale); - // fetch custom style from config - customStyle = templateAuthority.getProviderByRealm(realm).getConfig().getCustomStyle(); + // // fetch custom style from config + // customStyle = templateAuthority.getProviderByRealm(realm).getConfig().getCustomStyle(); } catch (NoSuchAuthorityException | NoSuchProviderException | NoSuchTemplateException e) { // skip templates on error } + // fetch custom style from config + if(r.getTemplatesConfiguration() != null && r.getTemplatesConfiguration().getCustomStyle() != null) { + customStyle = r.getTemplatesConfiguration().getCustomStyle(); + } + modelAndView.addObject("template", template); modelAndView.addObject("footer", footer); modelAndView.addObject("customStyle", customStyle); diff --git a/src/main/java/it/smartcommunitylab/aac/templates/base/AbstractTemplateProvider.java b/src/main/java/it/smartcommunitylab/aac/templates/base/AbstractTemplateProvider.java index 041d4cc51..bf9418529 100644 --- a/src/main/java/it/smartcommunitylab/aac/templates/base/AbstractTemplateProvider.java +++ b/src/main/java/it/smartcommunitylab/aac/templates/base/AbstractTemplateProvider.java @@ -62,6 +62,7 @@ public void afterPropertiesSet() throws Exception { } @Override + @Deprecated public Collection getLanguages() { return config.getLanguages().stream().map(l -> l.getValue()).collect(Collectors.toList()); } diff --git a/src/main/java/it/smartcommunitylab/aac/templates/base/AbstractTemplateProviderConfig.java b/src/main/java/it/smartcommunitylab/aac/templates/base/AbstractTemplateProviderConfig.java index 73df2587a..5044af5ea 100644 --- a/src/main/java/it/smartcommunitylab/aac/templates/base/AbstractTemplateProviderConfig.java +++ b/src/main/java/it/smartcommunitylab/aac/templates/base/AbstractTemplateProviderConfig.java @@ -77,6 +77,7 @@ protected AbstractTemplateProviderConfig() { } @Override + @Deprecated public Set getLanguages() { return !CollectionUtils.isEmpty(settingsMap.getLanguages()) ? settingsMap.getLanguages() @@ -84,6 +85,7 @@ public Set getLanguages() { } @Override + @Deprecated public String getCustomStyle() { return StringUtils.hasText(settingsMap.getCustomStyle()) ? settingsMap.getCustomStyle() : ""; } diff --git a/src/main/java/it/smartcommunitylab/aac/templates/model/LocalizationConfigurationMap.java b/src/main/java/it/smartcommunitylab/aac/templates/model/LocalizationConfigurationMap.java index c16132162..d988ea08b 100644 --- a/src/main/java/it/smartcommunitylab/aac/templates/model/LocalizationConfigurationMap.java +++ b/src/main/java/it/smartcommunitylab/aac/templates/model/LocalizationConfigurationMap.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -29,6 +30,7 @@ import javax.validation.Valid; @Valid +@JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public class LocalizationConfigurationMap implements ConfigurableProperties { diff --git a/src/main/java/it/smartcommunitylab/aac/templates/model/TemplatesConfigurationMap.java b/src/main/java/it/smartcommunitylab/aac/templates/model/TemplatesConfigurationMap.java new file mode 100644 index 000000000..073480b8e --- /dev/null +++ b/src/main/java/it/smartcommunitylab/aac/templates/model/TemplatesConfigurationMap.java @@ -0,0 +1,67 @@ +/* + * Copyright 2023 the original author or authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package it.smartcommunitylab.aac.templates.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import it.smartcommunitylab.aac.core.model.ConfigurableProperties; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import javax.validation.Valid; + +@Valid +@JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class TemplatesConfigurationMap implements ConfigurableProperties { + + private static ObjectMapper mapper = new ObjectMapper(); + private static final TypeReference> typeRef = + new TypeReference>() {}; + + private String customStyle; + + public String getCustomStyle() { + return customStyle; + } + + public void setCustomStyle(String customStyle) { + this.customStyle = customStyle; + } + + @Override + @JsonIgnore + public Map getConfiguration() { + // use mapper + mapper.setSerializationInclusion(Include.NON_EMPTY); + return mapper.convertValue(this, typeRef); + } + + @Override + @JsonIgnore + public void setConfiguration(Map props) { + // use mapper + mapper.setSerializationInclusion(Include.NON_EMPTY); + TemplatesConfigurationMap map = mapper.convertValue(props, TemplatesConfigurationMap.class); + + this.customStyle = map.getCustomStyle(); + } +} diff --git a/src/main/java/it/smartcommunitylab/aac/templates/provider/TemplateProviderSettingsMap.java b/src/main/java/it/smartcommunitylab/aac/templates/provider/TemplateProviderSettingsMap.java index bc9d34ddc..fe40e3fee 100644 --- a/src/main/java/it/smartcommunitylab/aac/templates/provider/TemplateProviderSettingsMap.java +++ b/src/main/java/it/smartcommunitylab/aac/templates/provider/TemplateProviderSettingsMap.java @@ -38,9 +38,13 @@ public class TemplateProviderSettingsMap extends AbstractSettingsMap { public static final String RESOURCE_TYPE = SystemKeys.RESOURCE_SETTINGS + SystemKeys.ID_SEPARATOR + SystemKeys.RESOURCE_TEMPLATE_PROVIDER; + @Deprecated private Set languages; + + @Deprecated private String customStyle; + @Deprecated public Set getLanguages() { return languages; } @@ -49,6 +53,7 @@ public void setLanguages(Set languages) { this.languages = languages; } + @Deprecated public String getCustomStyle() { return customStyle; } diff --git a/src/main/java/it/smartcommunitylab/aac/tos/TosConfigurationMap.java b/src/main/java/it/smartcommunitylab/aac/tos/TosConfigurationMap.java index ac759eb5b..dfd5ec158 100644 --- a/src/main/java/it/smartcommunitylab/aac/tos/TosConfigurationMap.java +++ b/src/main/java/it/smartcommunitylab/aac/tos/TosConfigurationMap.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -28,6 +29,7 @@ import javax.validation.Valid; @Valid +@JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public class TosConfigurationMap implements ConfigurableProperties { diff --git a/src/main/java/it/smartcommunitylab/aac/users/MyUserManager.java b/src/main/java/it/smartcommunitylab/aac/users/MyUserManager.java index faa512827..424cf421a 100644 --- a/src/main/java/it/smartcommunitylab/aac/users/MyUserManager.java +++ b/src/main/java/it/smartcommunitylab/aac/users/MyUserManager.java @@ -204,6 +204,9 @@ public Realm getMyRealm() throws NoSuchRealmException { Realm realm = realmService.getRealm(slug); // make sure config is clear realm.setOAuthConfiguration(null); + realm.setTosConfiguration(null); + realm.setLocalizationConfiguration(null); + realm.setTemplatesConfiguration(null); return realm; } diff --git a/src/main/java/it/smartcommunitylab/aac/users/controller/BaseUserController.java b/src/main/java/it/smartcommunitylab/aac/users/controller/BaseUserController.java index da030e93b..b4711aa50 100644 --- a/src/main/java/it/smartcommunitylab/aac/users/controller/BaseUserController.java +++ b/src/main/java/it/smartcommunitylab/aac/users/controller/BaseUserController.java @@ -19,11 +19,10 @@ import io.swagger.v3.oas.annotations.Operation; import it.smartcommunitylab.aac.Config; import it.smartcommunitylab.aac.SystemKeys; -import it.smartcommunitylab.aac.accounts.base.AbstractEditableAccount; import it.smartcommunitylab.aac.accounts.base.AbstractUserAccount; -import it.smartcommunitylab.aac.accounts.model.EditableUserAccount; import it.smartcommunitylab.aac.accounts.model.UserAccount; import it.smartcommunitylab.aac.common.NoSuchAuthorityException; +import it.smartcommunitylab.aac.common.NoSuchGroupException; import it.smartcommunitylab.aac.common.NoSuchProviderException; import it.smartcommunitylab.aac.common.NoSuchRealmException; import it.smartcommunitylab.aac.common.NoSuchUserException; @@ -31,10 +30,16 @@ import it.smartcommunitylab.aac.dto.UserEmail; import it.smartcommunitylab.aac.dto.UserStatus; import it.smartcommunitylab.aac.dto.UserSubject; +import it.smartcommunitylab.aac.groups.GroupManager; import it.smartcommunitylab.aac.model.SubjectStatus; import it.smartcommunitylab.aac.model.User; +import it.smartcommunitylab.aac.roles.RealmRoleManager; import it.smartcommunitylab.aac.users.UserManager; + +import java.util.ArrayList; import java.util.Collection; +import java.util.List; + import javax.validation.Valid; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; @@ -43,6 +48,7 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.util.Assert; @@ -64,6 +70,8 @@ public class BaseUserController implements InitializingBean { private final Logger logger = LoggerFactory.getLogger(getClass()); protected UserManager userManager; + protected GroupManager groupManager; + protected RealmRoleManager roleManager; @Override public void afterPropertiesSet() throws Exception { @@ -75,6 +83,15 @@ public void setUserManager(UserManager userManager) { this.userManager = userManager; } + @Autowired + public void setGroupManager(GroupManager groupManager) { + this.groupManager = groupManager; + } + + @Autowired + public void setRoleManager(RealmRoleManager roleManager) { + this.roleManager = roleManager; + } public String getAuthority() { return Config.R_USER; } @@ -88,10 +105,30 @@ public String getAuthority() { public Page listUser( @PathVariable @Valid @NotNull @Pattern(regexp = SystemKeys.SLUG_PATTERN) String realm, @RequestParam(required = false) String q, + @RequestParam(required = false) String group, + @RequestParam(required = false) String role, Pageable pageRequest - ) throws NoSuchRealmException { + ) throws NoSuchRealmException, NoSuchGroupException { logger.debug("list users for realm {}", StringUtils.trimAllWhitespace(realm)); + if(group != null) { + //list members for group + String[] userIds = groupManager.getGroupMembers(realm, group).toArray(new String[0]); + + List users = new ArrayList<>(); + for(int i = 0; i< userIds.length; i++) { + if(pageRequest == null || (i >= pageRequest.getOffset() && i <=pageRequest.getOffset()+pageRequest.getPageSize())) { + try { + users.add(userManager.getUser(realm, userIds[i])); + } catch (NoSuchUserException nue) { + //skip, the id may refer to another entity + } + } + } + + return new PageImpl<>(users, pageRequest, userIds.length); + } + // list users owned or accessible by this realm return userManager.searchUsers(realm, q, pageRequest); } diff --git a/src/main/java/org/springframework/security/oauth2/common/DefaultExpiringOAuth2RefreshToken.java b/src/main/java/org/springframework/security/oauth2/common/DefaultExpiringOAuth2RefreshToken.java new file mode 100644 index 000000000..ff7910ece --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/DefaultExpiringOAuth2RefreshToken.java @@ -0,0 +1,33 @@ +package org.springframework.security.oauth2.common; + +import java.util.Date; + +/** + *

+ * + * @author Ryan Heaton + */ +public class DefaultExpiringOAuth2RefreshToken extends DefaultOAuth2RefreshToken implements ExpiringOAuth2RefreshToken { + + private static final long serialVersionUID = 3449554332764129719L; + + private final Date expiration; + + /** + * @param value + */ + public DefaultExpiringOAuth2RefreshToken(String value, Date expiration) { + super(value); + this.expiration = expiration; + } + + /** + * The instant the token expires. + * + * @return The instant the token expires. + */ + public Date getExpiration() { + return expiration; + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/common/DefaultOAuth2AccessToken.java b/src/main/java/org/springframework/security/oauth2/common/DefaultOAuth2AccessToken.java new file mode 100644 index 000000000..38e64c107 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/DefaultOAuth2AccessToken.java @@ -0,0 +1,241 @@ +package org.springframework.security.oauth2.common; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeSet; + +/** + * Basic access token for OAuth 2. + * + *

+ * + * @author Ryan Heaton + * @author Dave Syer + * @author Rob Winch + */ +public class DefaultOAuth2AccessToken implements Serializable, OAuth2AccessToken { + + private static final long serialVersionUID = 914967629530462926L; + + private String value; + + private Date expiration; + + private String tokenType = BEARER_TYPE.toLowerCase(); + + private OAuth2RefreshToken refreshToken; + + private Set scope; + + private Map additionalInformation = Collections.emptyMap(); + + /** + * Create an access token from the value provided. + */ + public DefaultOAuth2AccessToken(String value) { + this.value = value; + } + + /** + * Private constructor for JPA and other serialization tools. + */ + @SuppressWarnings("unused") + private DefaultOAuth2AccessToken() { + this((String) null); + } + + /** + * Copy constructor for access token. + * + * @param accessToken + */ + public DefaultOAuth2AccessToken(OAuth2AccessToken accessToken) { + this(accessToken.getValue()); + setAdditionalInformation(accessToken.getAdditionalInformation()); + setRefreshToken(accessToken.getRefreshToken()); + setExpiration(accessToken.getExpiration()); + setScope(accessToken.getScope()); + setTokenType(accessToken.getTokenType()); + } + + public void setValue(String value) { + this.value = value; + } + + /** + * The token value. + * + * @return The token value. + */ + public String getValue() { + return value; + } + + public int getExpiresIn() { + return expiration != null ? Long.valueOf((expiration.getTime() - System.currentTimeMillis()) / 1000L) + .intValue() : 0; + } + + protected void setExpiresIn(int delta) { + setExpiration(new Date(System.currentTimeMillis() + delta)); + } + + /** + * The instant the token expires. + * + * @return The instant the token expires. + */ + public Date getExpiration() { + return expiration; + } + + /** + * The instant the token expires. + * + * @param expiration The instant the token expires. + */ + public void setExpiration(Date expiration) { + this.expiration = expiration; + } + + /** + * Convenience method for checking expiration + * + * @return true if the expiration is befor ethe current time + */ + public boolean isExpired() { + return expiration != null && expiration.before(new Date()); + } + + /** + * The token type, as introduced in draft 11 of the OAuth 2 spec. The spec doesn't define (yet) that the valid token + * types are, but says it's required so the default will just be "undefined". + * + * @return The token type, as introduced in draft 11 of the OAuth 2 spec. + */ + public String getTokenType() { + return tokenType; + } + + /** + * The token type, as introduced in draft 11 of the OAuth 2 spec. + * + * @param tokenType The token type, as introduced in draft 11 of the OAuth 2 spec. + */ + public void setTokenType(String tokenType) { + this.tokenType = tokenType; + } + + /** + * The refresh token associated with the access token, if any. + * + * @return The refresh token associated with the access token, if any. + */ + public OAuth2RefreshToken getRefreshToken() { + return refreshToken; + } + + /** + * The refresh token associated with the access token, if any. + * + * @param refreshToken The refresh token associated with the access token, if any. + */ + public void setRefreshToken(OAuth2RefreshToken refreshToken) { + this.refreshToken = refreshToken; + } + + /** + * The scope of the token. + * + * @return The scope of the token. + */ + public Set getScope() { + return scope; + } + + /** + * The scope of the token. + * + * @param scope The scope of the token. + */ + public void setScope(Set scope) { + this.scope = scope; + } + + @Override + public boolean equals(Object obj) { + return obj != null && toString().equals(obj.toString()); + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + @Override + public String toString() { + return String.valueOf(getValue()); + } + + public static OAuth2AccessToken valueOf(Map tokenParams) { + DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(tokenParams.get(ACCESS_TOKEN)); + + if (tokenParams.containsKey(EXPIRES_IN)) { + long expiration = 0; + try { + expiration = Long.parseLong(String.valueOf(tokenParams.get(EXPIRES_IN))); + } + catch (NumberFormatException e) { + // fall through... + } + token.setExpiration(new Date(System.currentTimeMillis() + (expiration * 1000L))); + } + + if (tokenParams.containsKey(REFRESH_TOKEN)) { + String refresh = tokenParams.get(REFRESH_TOKEN); + DefaultOAuth2RefreshToken refreshToken = new DefaultOAuth2RefreshToken(refresh); + token.setRefreshToken(refreshToken); + } + + if (tokenParams.containsKey(SCOPE)) { + Set scope = new TreeSet(); + for (StringTokenizer tokenizer = new StringTokenizer(tokenParams.get(SCOPE), " ,"); tokenizer + .hasMoreTokens();) { + scope.add(tokenizer.nextToken()); + } + token.setScope(scope); + } + + if (tokenParams.containsKey(TOKEN_TYPE)) { + token.setTokenType(tokenParams.get(TOKEN_TYPE)); + } + + return token; + } + + /** + * Additional information that token granters would like to add to the token, e.g. to support new token types. + * + * @return the additional information (default empty) + */ + public Map getAdditionalInformation() { + return additionalInformation; + } + + /** + * Additional information that token granters would like to add to the token, e.g. to support new token types. If + * the values in the map are primitive then remote communication is going to always work. It should also be safe to + * use maps (nested if desired), or something that is explicitly serializable by Jackson. + * + * @param additionalInformation the additional information to set + */ + public void setAdditionalInformation(Map additionalInformation) { + this.additionalInformation = new LinkedHashMap(additionalInformation); + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/common/DefaultOAuth2RefreshToken.java b/src/main/java/org/springframework/security/oauth2/common/DefaultOAuth2RefreshToken.java new file mode 100644 index 000000000..17ce2f90b --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/DefaultOAuth2RefreshToken.java @@ -0,0 +1,73 @@ +package org.springframework.security.oauth2.common; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * An OAuth 2 refresh token. + * + *

+ * + * @author Ryan Heaton + * @author Dave Syer + */ +public class DefaultOAuth2RefreshToken implements Serializable, OAuth2RefreshToken { + + private static final long serialVersionUID = 8349970621900575838L; + + private String value; + + /** + * Create a new refresh token. + */ + @JsonCreator + public DefaultOAuth2RefreshToken(String value) { + this.value = value; + } + + /** + * Default constructor for JPA and other serialization tools. + */ + @SuppressWarnings("unused") + private DefaultOAuth2RefreshToken() { + this(null); + } + + /* (non-Javadoc) + * @see org.springframework.security.oauth2.common.IFOO#getValue() + */ + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return getValue(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof DefaultOAuth2RefreshToken)) { + return false; + } + + DefaultOAuth2RefreshToken that = (DefaultOAuth2RefreshToken) o; + + if (value != null ? !value.equals(that.value) : that.value != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return value != null ? value.hashCode() : 0; + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/DefaultThrowableAnalyzer.java b/src/main/java/org/springframework/security/oauth2/common/DefaultThrowableAnalyzer.java new file mode 100644 index 000000000..f88d39b29 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/DefaultThrowableAnalyzer.java @@ -0,0 +1,28 @@ +package org.springframework.security.oauth2.common; + +import org.springframework.security.web.util.ThrowableAnalyzer; +import org.springframework.security.web.util.ThrowableCauseExtractor; + +import javax.servlet.ServletException; + +/** + * Default implementation of ThrowableAnalyzer which is capable of also unwrapping + * ServletExceptions. + * + *

+ */ +public final class DefaultThrowableAnalyzer extends ThrowableAnalyzer { + /** + * @see org.springframework.security.web.util.ThrowableAnalyzer#initExtractorMap() + */ + protected void initExtractorMap() { + super.initExtractorMap(); + + registerExtractor(ServletException.class, new ThrowableCauseExtractor() { + public Throwable extractCause(Throwable throwable) { + ThrowableAnalyzer.verifyThrowableHierarchy(throwable, ServletException.class); + return ((ServletException) throwable).getRootCause(); + } + }); + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/ExpiringOAuth2RefreshToken.java b/src/main/java/org/springframework/security/oauth2/common/ExpiringOAuth2RefreshToken.java new file mode 100644 index 000000000..815b5586a --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/ExpiringOAuth2RefreshToken.java @@ -0,0 +1,27 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.common; + +import java.util.Date; + +/** + *

+ * + * @author Dave Syer + * + */ +public interface ExpiringOAuth2RefreshToken extends OAuth2RefreshToken { + + Date getExpiration(); + +} diff --git a/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessToken.java b/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessToken.java new file mode 100644 index 000000000..49c38b475 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessToken.java @@ -0,0 +1,86 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.common; + +import java.io.Serializable; +import java.util.Date; +import java.util.Map; +import java.util.Set; + +/** + *

+ * + * @author Dave Syer + * + */ +@com.fasterxml.jackson.databind.annotation.JsonSerialize(using = OAuth2AccessTokenJackson2Serializer.class) +@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = OAuth2AccessTokenJackson2Deserializer.class) +public interface OAuth2AccessToken { + + public static String BEARER_TYPE = "Bearer"; + + public static String OAUTH2_TYPE = "OAuth2"; + + /** + * The access token issued by the authorization server. This value is REQUIRED. + */ + public static String ACCESS_TOKEN = "access_token"; + + /** + * The type of the token issued as described in Section 7.1. Value is case insensitive. + * This value is REQUIRED. + */ + public static String TOKEN_TYPE = "token_type"; + + /** + * The lifetime in seconds of the access token. For example, the value "3600" denotes that the access token will + * expire in one hour from the time the response was generated. This value is OPTIONAL. + */ + public static String EXPIRES_IN = "expires_in"; + + /** + * The refresh token which can be used to obtain new access tokens using the same authorization grant as described + * in Section 6. This value is OPTIONAL. + */ + public static String REFRESH_TOKEN = "refresh_token"; + + /** + * The scope of the access token as described by Section 3.3 + */ + public static String SCOPE = "scope"; + + /** + * The additionalInformation map is used by the token serializers to export any fields used by extensions of OAuth. + * @return a map from the field name in the serialized token to the value to be exported. The default serializers + * make use of Jackson's automatic JSON mapping for Java objects (for the Token Endpoint flows) or implicitly call + * .toString() on the "value" object (for the implicit flow) as part of the serialization process. + */ + Map getAdditionalInformation(); + + Set getScope(); + + OAuth2RefreshToken getRefreshToken(); + + String getTokenType(); + + boolean isExpired(); + + Date getExpiration(); + + int getExpiresIn(); + + String getValue(); + +} diff --git a/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessTokenJackson2Deserializer.java b/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessTokenJackson2Deserializer.java new file mode 100644 index 000000000..52efcd62e --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessTokenJackson2Deserializer.java @@ -0,0 +1,123 @@ +/* + * Copyright 2006-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.common; + + +import java.io.IOException; +import java.io.Serializable; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.springframework.security.oauth2.common.util.OAuth2Utils; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +/** + *

+ * Provides the ability to deserialize JSON response into an {@link org.springframework.security.oauth2.common.OAuth2AccessToken} with jackson2 by implementing + * {@link com.fasterxml.jackson.databind.JsonDeserializer}. + *

+ *

+ * The expected format of the access token is defined by Successful Response. + *

+ * + *

+ * + * @author Rob Winch + * @author Brian Clozel + * @see org.springframework.security.oauth2.common.OAuth2AccessTokenJackson2Serializer + */ +@SuppressWarnings("serial") +public final class OAuth2AccessTokenJackson2Deserializer extends StdDeserializer { + + public OAuth2AccessTokenJackson2Deserializer() { + super(OAuth2AccessToken.class); + } + + @Override + public OAuth2AccessToken deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, + JsonProcessingException { + + String tokenValue = null; + String tokenType = null; + String refreshToken = null; + Long expiresIn = null; + Set scope = null; + Map additionalInformation = new LinkedHashMap(); + + // TODO What should occur if a parameter exists twice + while (jp.nextToken() != JsonToken.END_OBJECT) { + String name = jp.getCurrentName(); + jp.nextToken(); + if (OAuth2AccessToken.ACCESS_TOKEN.equals(name)) { + tokenValue = jp.getText(); + } + else if (OAuth2AccessToken.TOKEN_TYPE.equals(name)) { + tokenType = jp.getText(); + } + else if (OAuth2AccessToken.REFRESH_TOKEN.equals(name)) { + refreshToken = jp.getText(); + } + else if (OAuth2AccessToken.EXPIRES_IN.equals(name)) { + try { + expiresIn = jp.getLongValue(); + } catch (JsonParseException e) { + expiresIn = Long.valueOf(jp.getText()); + } + } + else if (OAuth2AccessToken.SCOPE.equals(name)) { + scope = parseScope(jp); + } else { + additionalInformation.put(name, jp.readValueAs(Serializable.class)); + } + } + + // TODO What should occur if a required parameter (tokenValue or tokenType) is missing? + + DefaultOAuth2AccessToken accessToken = new DefaultOAuth2AccessToken(tokenValue); + accessToken.setTokenType(tokenType); + if (expiresIn != null && expiresIn != 0) { + accessToken.setExpiration(new Date(System.currentTimeMillis() + (expiresIn * 1000))); + } + if (refreshToken != null) { + accessToken.setRefreshToken(new DefaultOAuth2RefreshToken(refreshToken)); + } + accessToken.setScope(scope); + accessToken.setAdditionalInformation(additionalInformation); + + return accessToken; + } + + private Set parseScope(JsonParser jp) throws JsonParseException, IOException { + Set scope; + if (jp.getCurrentToken() == JsonToken.START_ARRAY) { + scope = new TreeSet(); + while (jp.nextToken() != JsonToken.END_ARRAY) { + scope.add(jp.getValueAsString()); + } + } else { + String text = jp.getText(); + scope = OAuth2Utils.parseParameterList(text); + } + return scope; + } +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessTokenJackson2Serializer.java b/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessTokenJackson2Serializer.java new file mode 100644 index 000000000..1ee521e50 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessTokenJackson2Serializer.java @@ -0,0 +1,76 @@ +/* + * Copyright 2006-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.common; + +import java.io.IOException; +import java.io.Serializable; +import java.util.Date; +import java.util.Map; +import java.util.Set; + +import org.springframework.util.Assert; + +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +/** + * Provides the ability to serialize an {@link org.springframework.security.oauth2.common.OAuth2AccessToken} with jackson2 by implementing {@link com.fasterxml.jackson.databind.JsonDeserializer}. + * + * The expected format of the access token is defined by Successful Response. + * + *

+ * + * @author Rob Winch + * @author Brian Clozel + * @see org.springframework.security.oauth2.common.OAuth2AccessTokenJackson2Deserializer + */ +public final class OAuth2AccessTokenJackson2Serializer extends StdSerializer { + + public OAuth2AccessTokenJackson2Serializer() { + super(OAuth2AccessToken.class); + } + + @Override + public void serialize(OAuth2AccessToken token, JsonGenerator jgen, SerializerProvider provider) throws IOException, + JsonGenerationException { + jgen.writeStartObject(); + jgen.writeStringField(OAuth2AccessToken.ACCESS_TOKEN, token.getValue()); + jgen.writeStringField(OAuth2AccessToken.TOKEN_TYPE, token.getTokenType()); + OAuth2RefreshToken refreshToken = token.getRefreshToken(); + if (refreshToken != null) { + jgen.writeStringField(OAuth2AccessToken.REFRESH_TOKEN, refreshToken.getValue()); + } + Date expiration = token.getExpiration(); + if (expiration != null) { + long now = System.currentTimeMillis(); + jgen.writeNumberField(OAuth2AccessToken.EXPIRES_IN, (expiration.getTime() - now) / 1000); + } + Set scope = token.getScope(); + if (scope != null && !scope.isEmpty()) { + StringBuffer scopes = new StringBuffer(); + for (String s : scope) { + Assert.hasLength(s, "Scopes cannot be null or empty. Got " + scope + ""); + scopes.append(s); + scopes.append(" "); + } + jgen.writeStringField(OAuth2AccessToken.SCOPE, scopes.substring(0, scopes.length() - 1)); + } + Map additionalInformation = token.getAdditionalInformation(); + for (String key : additionalInformation.keySet()) { + jgen.writeObjectField(key, additionalInformation.get(key)); + } + jgen.writeEndObject(); + } +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/common/OAuth2RefreshToken.java b/src/main/java/org/springframework/security/oauth2/common/OAuth2RefreshToken.java new file mode 100644 index 000000000..15aacff03 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/OAuth2RefreshToken.java @@ -0,0 +1,33 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.common; + +import com.fasterxml.jackson.annotation.JsonValue; + +/** + *

+ * + * @author Dave Syer + * + */ +public interface OAuth2RefreshToken { + + /** + * The value of the token. + * + * @return The value of the token. + */ + @JsonValue + String getValue(); + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/BadClientCredentialsException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/BadClientCredentialsException.java new file mode 100644 index 000000000..f84772738 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/BadClientCredentialsException.java @@ -0,0 +1,27 @@ +package org.springframework.security.oauth2.common.exceptions; + +/** + * Exception thrown when a client was unable to authenticate. + * + *

+ * + * @author Ryan Heaton + * @author Dave Syer + */ +@SuppressWarnings("serial") +public class BadClientCredentialsException extends ClientAuthenticationException { + + public BadClientCredentialsException() { + super("Bad client credentials"); // Don't reveal source of error + } + + @Override + public int getHttpErrorCode() { + return 401; + } + + @Override + public String getOAuth2ErrorCode() { + return "invalid_client"; + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/ClientAuthenticationException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/ClientAuthenticationException.java new file mode 100644 index 000000000..0f4485c43 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/ClientAuthenticationException.java @@ -0,0 +1,30 @@ +package org.springframework.security.oauth2.common.exceptions; + +/** + * Base exception + * + *

+ * + * @author Ryan Heaton + * @author Dave Syer + */ +@SuppressWarnings("serial") +public abstract class ClientAuthenticationException extends OAuth2Exception { + + public ClientAuthenticationException(String msg, Throwable t) { + super(msg, t); + } + + public ClientAuthenticationException(String msg) { + super(msg); + } + + @Override + public int getHttpErrorCode() { + // The spec says this is a bad request (not unauthorized) + return 400; + } + + @Override + public abstract String getOAuth2ErrorCode(); +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/InsufficientScopeException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/InsufficientScopeException.java new file mode 100644 index 000000000..256bc574f --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/InsufficientScopeException.java @@ -0,0 +1,39 @@ +package org.springframework.security.oauth2.common.exceptions; + +import java.util.Set; + +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.oauth2.common.util.OAuth2Utils; + +/** + * Exception representing insufficient scope in a token when a request is handled by a Resource Server. It is akin to an + * {@link AccessDeniedException} and should result in a 403 (FORBIDDEN) HTTP status. + * + *

+ * + * @author Dave Syer + */ +@SuppressWarnings("serial") +public class InsufficientScopeException extends OAuth2Exception { + + public InsufficientScopeException(String msg, Set validScope) { + this(msg); + addAdditionalInformation("scope", OAuth2Utils.formatParameterList(validScope)); + } + + public InsufficientScopeException(String msg) { + super(msg); + } + + @Override + public int getHttpErrorCode() { + return 403; + } + + @Override + public String getOAuth2ErrorCode() { + // Not defined in the spec, so not really an OAuth2Exception + return "insufficient_scope"; + } + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidClientException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidClientException.java new file mode 100644 index 000000000..3e25aefde --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidClientException.java @@ -0,0 +1,27 @@ +package org.springframework.security.oauth2.common.exceptions; + +/** + * Exception thrown when a client was unable to authenticate. + * + *

+ * + * @author Ryan Heaton + * @author Dave Syer + */ +@SuppressWarnings("serial") +public class InvalidClientException extends ClientAuthenticationException { + + public InvalidClientException(String msg) { + super(msg); + } + + @Override + public int getHttpErrorCode() { + return 401; + } + + @Override + public String getOAuth2ErrorCode() { + return "invalid_client"; + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidGrantException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidGrantException.java new file mode 100644 index 000000000..405849d39 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidGrantException.java @@ -0,0 +1,24 @@ +package org.springframework.security.oauth2.common.exceptions; + +/** + *

+ * + * @author Ryan Heaton + * @author Dave Syer + */ +@SuppressWarnings("serial") +public class InvalidGrantException extends ClientAuthenticationException { + + public InvalidGrantException(String msg, Throwable t) { + super(msg, t); + } + + public InvalidGrantException(String msg) { + super(msg); + } + + @Override + public String getOAuth2ErrorCode() { + return "invalid_grant"; + } +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidRequestException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidRequestException.java new file mode 100644 index 000000000..fcf142bde --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidRequestException.java @@ -0,0 +1,23 @@ +package org.springframework.security.oauth2.common.exceptions; + +/** + *

+ * + * @author Dave Syer + */ +@SuppressWarnings("serial") +public class InvalidRequestException extends ClientAuthenticationException { + + public InvalidRequestException(String msg, Throwable t) { + super(msg, t); + } + + public InvalidRequestException(String msg) { + super(msg); + } + + @Override + public String getOAuth2ErrorCode() { + return "invalid_request"; + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidScopeException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidScopeException.java new file mode 100644 index 000000000..cff71d215 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidScopeException.java @@ -0,0 +1,34 @@ +package org.springframework.security.oauth2.common.exceptions; + +import java.util.Set; + +import org.springframework.security.oauth2.common.util.OAuth2Utils; + +/** + * Exception representing an invalid scope in a token or authorization request (i.e. from an Authorization Server). Note + * that this is not the same as an access denied exception if the scope presented to a Resource Server is insufficient. + * The spec in this case mandates a 400 status code. + * + *

+ * + * @author Ryan Heaton + * @author Dave Syer + */ +@SuppressWarnings("serial") +public class InvalidScopeException extends OAuth2Exception { + + public InvalidScopeException(String msg, Set validScope) { + this(msg); + addAdditionalInformation("scope", OAuth2Utils.formatParameterList(validScope)); + } + + public InvalidScopeException(String msg) { + super(msg); + } + + @Override + public String getOAuth2ErrorCode() { + return "invalid_scope"; + } + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidTokenException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidTokenException.java new file mode 100644 index 000000000..6368134ee --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/InvalidTokenException.java @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.oauth2.common.exceptions; + +/** + *

+ * + * @author Ryan Heaton + * @author Dave Syer + */ +@SuppressWarnings("serial") +public class InvalidTokenException extends ClientAuthenticationException { + + public InvalidTokenException(String msg, Throwable t) { + super(msg, t); + } + + public InvalidTokenException(String msg) { + super(msg); + } + + @Override + public int getHttpErrorCode() { + return 401; + } + + @Override + public String getOAuth2ErrorCode() { + return "invalid_token"; + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/OAuth2AccessDeniedException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/OAuth2AccessDeniedException.java new file mode 100644 index 000000000..921cbcf9a --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/OAuth2AccessDeniedException.java @@ -0,0 +1,35 @@ +package org.springframework.security.oauth2.common.exceptions; + +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; + +/** + * When access is denied we usually want a 403, but we want the same treatment + * as all the other OAuth2Exception types, so this is not a Spring Security + * AccessDeniedException. + * + *

+ * + * @author Ryan Heaton + * @author Dave Syer + */ +@SuppressWarnings("serial") +public class OAuth2AccessDeniedException extends OAuth2Exception { + + public OAuth2AccessDeniedException() { + super("OAuth2 access denied."); + } + + public OAuth2AccessDeniedException(String msg) { + super(msg); + } + + @Override + public String getOAuth2ErrorCode() { + return "access_denied"; + } + + @Override + public int getHttpErrorCode() { + return 403; + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/OAuth2Exception.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/OAuth2Exception.java new file mode 100644 index 000000000..e50338e99 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/OAuth2Exception.java @@ -0,0 +1,192 @@ +package org.springframework.security.oauth2.common.exceptions; + +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +/** + * Base exception for OAuth 2 exceptions. + * + *

+ * + * @author Ryan Heaton + * @author Rob Winch + * @author Dave Syer + */ +@SuppressWarnings("serial") +@com.fasterxml.jackson.databind.annotation.JsonSerialize(using = OAuth2ExceptionJackson2Serializer.class) +@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = OAuth2ExceptionJackson2Deserializer.class) +public class OAuth2Exception extends RuntimeException { + + public static final String ERROR = "error"; + public static final String DESCRIPTION = "error_description"; + public static final String URI = "error_uri"; + public static final String INVALID_REQUEST = "invalid_request"; + public static final String INVALID_CLIENT = "invalid_client"; + public static final String INVALID_GRANT = "invalid_grant"; + public static final String UNAUTHORIZED_CLIENT = "unauthorized_client"; + public static final String UNSUPPORTED_GRANT_TYPE = "unsupported_grant_type"; + public static final String INVALID_SCOPE = "invalid_scope"; + public static final String INSUFFICIENT_SCOPE = "insufficient_scope"; + public static final String INVALID_TOKEN = "invalid_token"; + public static final String REDIRECT_URI_MISMATCH ="redirect_uri_mismatch"; + public static final String UNSUPPORTED_RESPONSE_TYPE ="unsupported_response_type"; + public static final String ACCESS_DENIED = "access_denied"; + + private Map additionalInformation = null; + + public OAuth2Exception(String msg, Throwable t) { + super(msg, t); + } + + public OAuth2Exception(String msg) { + super(msg); + } + + /** + * The OAuth2 error code. + * + * @return The OAuth2 error code. + */ + public String getOAuth2ErrorCode() { + return "invalid_request"; + } + + /** + * The HTTP error code associated with this error. + * + * @return The HTTP error code associated with this error. + */ + public int getHttpErrorCode() { + return 400; + } + + /** + * Get any additional information associated with this error. + * + * @return Additional information, or null if none. + */ + public Map getAdditionalInformation() { + return this.additionalInformation; + } + + /** + * Add some additional information with this OAuth error. + * + * @param key The key. + * @param value The value. + */ + public void addAdditionalInformation(String key, String value) { + if (this.additionalInformation == null) { + this.additionalInformation = new TreeMap(); + } + + this.additionalInformation.put(key, value); + + } + + /** + * Creates the appropriate subclass of OAuth2Exception given the errorCode. + * @param errorCode + * @param errorMessage + * @return + */ + public static OAuth2Exception create(String errorCode, String errorMessage) { + if (errorMessage == null) { + errorMessage = errorCode == null ? "OAuth Error" : errorCode; + } + if (INVALID_CLIENT.equals(errorCode)) { + return new InvalidClientException(errorMessage); + } + else if (UNAUTHORIZED_CLIENT.equals(errorCode)) { + return new UnauthorizedClientException(errorMessage); + } + else if (INVALID_GRANT.equals(errorCode)) { + return new InvalidGrantException(errorMessage); + } + else if (INVALID_SCOPE.equals(errorCode)) { + return new InvalidScopeException(errorMessage); + } + else if (INVALID_TOKEN.equals(errorCode)) { + return new InvalidTokenException(errorMessage); + } + else if (INVALID_REQUEST.equals(errorCode)) { + return new InvalidRequestException(errorMessage); + } + else if (REDIRECT_URI_MISMATCH.equals(errorCode)) { + return new RedirectMismatchException(errorMessage); + } + else if (UNSUPPORTED_GRANT_TYPE.equals(errorCode)) { + return new UnsupportedGrantTypeException(errorMessage); + } + else if (UNSUPPORTED_RESPONSE_TYPE.equals(errorCode)) { + return new UnsupportedResponseTypeException(errorMessage); + } + else if (ACCESS_DENIED.equals(errorCode)) { + return new UserDeniedAuthorizationException(errorMessage); + } + else { + return new OAuth2Exception(errorMessage); + } + } + + /** + * Creates an {@link OAuth2Exception} from a Map<String,String>. + * + * @param errorParams + * @return + */ + public static OAuth2Exception valueOf(Map errorParams) { + String errorCode = errorParams.get(ERROR); + String errorMessage = errorParams.containsKey(DESCRIPTION) ? errorParams.get(DESCRIPTION) + : null; + OAuth2Exception ex = create(errorCode, errorMessage); + Set> entries = errorParams.entrySet(); + for (Map.Entry entry : entries) { + String key = entry.getKey(); + if (!ERROR.equals(key) && !DESCRIPTION.equals(key)) { + ex.addAdditionalInformation(key, entry.getValue()); + } + } + + return ex; + } + + @Override + public String toString() { + return getSummary(); + } + + /** + * @return a comma-delimited list of details (key=value pairs) + */ + public String getSummary() { + + StringBuilder builder = new StringBuilder(); + + String delim = ""; + + String error = this.getOAuth2ErrorCode(); + if (error != null) { + builder.append(delim).append("error=\"").append(error).append("\""); + delim = ", "; + } + + String errorMessage = this.getMessage(); + if (errorMessage != null) { + builder.append(delim).append("error_description=\"").append(errorMessage).append("\""); + delim = ", "; + } + + Map additionalParams = this.getAdditionalInformation(); + if (additionalParams != null) { + for (Map.Entry param : additionalParams.entrySet()) { + builder.append(delim).append(param.getKey()).append("=\"").append(param.getValue()).append("\""); + delim = ", "; + } + } + + return builder.toString(); + + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/OAuth2ExceptionJackson2Deserializer.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/OAuth2ExceptionJackson2Deserializer.java new file mode 100644 index 000000000..92beca0bd --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/OAuth2ExceptionJackson2Deserializer.java @@ -0,0 +1,137 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.common.exceptions; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.security.oauth2.common.util.OAuth2Utils; + +/** + *

+ * + * @author Brian Clozel + * + */ +@SuppressWarnings("serial") +public class OAuth2ExceptionJackson2Deserializer extends StdDeserializer { + + public OAuth2ExceptionJackson2Deserializer() { + super(OAuth2Exception.class); + } + + @Override + public OAuth2Exception deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, + JsonProcessingException { + + JsonToken t = jp.getCurrentToken(); + if (t == JsonToken.START_OBJECT) { + t = jp.nextToken(); + } + Map errorParams = new HashMap(); + for (; t == JsonToken.FIELD_NAME; t = jp.nextToken()) { + // Must point to field name + String fieldName = jp.getCurrentName(); + // And then the value... + t = jp.nextToken(); + // Note: must handle null explicitly here; value deserializers won't + Object value; + if (t == JsonToken.VALUE_NULL) { + value = null; + } + // Some servers might send back complex content + else if (t == JsonToken.START_ARRAY) { + value = jp.readValueAs(List.class); + } + else if (t == JsonToken.START_OBJECT) { + value = jp.readValueAs(Map.class); + } + else { + value = jp.getText(); + } + errorParams.put(fieldName, value); + } + + Object errorCode = errorParams.get("error"); + String errorMessage = errorParams.get("error_description") != null ? errorParams.get("error_description").toString() : null; + if (errorMessage == null) { + errorMessage = errorCode == null ? "OAuth Error" : errorCode.toString(); + } + + OAuth2Exception ex; + if ("invalid_client".equals(errorCode)) { + ex = new InvalidClientException(errorMessage); + } + else if ("unauthorized_client".equals(errorCode)) { + ex = new UnauthorizedClientException(errorMessage); + } + else if ("invalid_grant".equals(errorCode)) { + if (errorMessage.toLowerCase().contains("redirect") && errorMessage.toLowerCase().contains("match")) { + ex = new RedirectMismatchException(errorMessage); + } + else { + ex = new InvalidGrantException(errorMessage); + } + } + else if ("invalid_scope".equals(errorCode)) { + ex = new InvalidScopeException(errorMessage); + } + else if ("invalid_token".equals(errorCode)) { + ex = new InvalidTokenException(errorMessage); + } + else if ("invalid_request".equals(errorCode)) { + ex = new InvalidRequestException(errorMessage); + } + else if ("redirect_uri_mismatch".equals(errorCode)) { + ex = new RedirectMismatchException(errorMessage); + } + else if ("unsupported_grant_type".equals(errorCode)) { + ex = new UnsupportedGrantTypeException(errorMessage); + } + else if ("unsupported_response_type".equals(errorCode)) { + ex = new UnsupportedResponseTypeException(errorMessage); + } + else if ("insufficient_scope".equals(errorCode)) { + ex = new InsufficientScopeException(errorMessage, OAuth2Utils.parseParameterList((String) errorParams + .get("scope"))); + } + else if ("access_denied".equals(errorCode)) { + ex = new UserDeniedAuthorizationException(errorMessage); + } + else { + ex = new OAuth2Exception(errorMessage); + } + + Set> entries = errorParams.entrySet(); + for (Map.Entry entry : entries) { + String key = entry.getKey(); + if (!"error".equals(key) && !"error_description".equals(key)) { + Object value = entry.getValue(); + ex.addAdditionalInformation(key, value == null ? null : value.toString()); + } + } + + return ex; + + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/OAuth2ExceptionJackson2Serializer.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/OAuth2ExceptionJackson2Serializer.java new file mode 100644 index 000000000..c176b35ba --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/OAuth2ExceptionJackson2Serializer.java @@ -0,0 +1,51 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.common.exceptions; + +import java.io.IOException; +import java.util.Map.Entry; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +/** + *

+ * + * @author Brian Clozel + * + */ +public class OAuth2ExceptionJackson2Serializer extends StdSerializer { + + public OAuth2ExceptionJackson2Serializer() { + super(OAuth2Exception.class); + } + + @Override + public void serialize(OAuth2Exception value, JsonGenerator jgen, SerializerProvider provider) throws IOException, + JsonProcessingException { + jgen.writeStartObject(); + jgen.writeStringField("error", value.getOAuth2ErrorCode()); + jgen.writeStringField("error_description", value.getMessage()); + if (value.getAdditionalInformation()!=null) { + for (Entry entry : value.getAdditionalInformation().entrySet()) { + String key = entry.getKey(); + String add = entry.getValue(); + jgen.writeStringField(key, add); + } + } + jgen.writeEndObject(); + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/RedirectMismatchException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/RedirectMismatchException.java new file mode 100644 index 000000000..6bb34d4d3 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/RedirectMismatchException.java @@ -0,0 +1,23 @@ +package org.springframework.security.oauth2.common.exceptions; + +/** + *

+ * + * @author Ryan Heaton + */ +@SuppressWarnings("serial") +public class RedirectMismatchException extends ClientAuthenticationException { + + public RedirectMismatchException(String msg, Throwable t) { + super(msg, t); + } + + public RedirectMismatchException(String msg) { + super(msg); + } + + @Override + public String getOAuth2ErrorCode() { + return "invalid_grant"; + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/SerializationException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/SerializationException.java new file mode 100644 index 000000000..5dd8f3f94 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/SerializationException.java @@ -0,0 +1,27 @@ +package org.springframework.security.oauth2.common.exceptions; + +/** + * Thrown during a problem serialization/deserialization. + * + *

+ * + * @author Ryan Heaton + */ +@SuppressWarnings("serial") +public class SerializationException extends RuntimeException { + + public SerializationException() { + } + + public SerializationException(String message) { + super(message); + } + + public SerializationException(String message, Throwable cause) { + super(message, cause); + } + + public SerializationException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/UnapprovedClientAuthenticationException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/UnapprovedClientAuthenticationException.java new file mode 100644 index 000000000..b86b6e340 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/UnapprovedClientAuthenticationException.java @@ -0,0 +1,20 @@ +package org.springframework.security.oauth2.common.exceptions; + +import org.springframework.security.authentication.InsufficientAuthenticationException; + +/** + *

+ * + * @author Ryan Heaton + */ +@SuppressWarnings("serial") +public class UnapprovedClientAuthenticationException extends InsufficientAuthenticationException { + + public UnapprovedClientAuthenticationException(String msg) { + super(msg); + } + + public UnapprovedClientAuthenticationException(String msg, Throwable t) { + super(msg, t); + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/UnauthorizedClientException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/UnauthorizedClientException.java new file mode 100644 index 000000000..88cca3f48 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/UnauthorizedClientException.java @@ -0,0 +1,31 @@ +package org.springframework.security.oauth2.common.exceptions; + +/** + * Exception thrown when a client was unable to authenticate. + * + *

+ * + * @author Ryan Heaton + */ +@SuppressWarnings("serial") +public class UnauthorizedClientException extends ClientAuthenticationException { + + public UnauthorizedClientException(String msg, Throwable t) { + super(msg, t); + } + + public UnauthorizedClientException(String msg) { + super(msg); + } + + @Override + public int getHttpErrorCode() { + // The spec says this can be unauthorized + return 401; + } + + @Override + public String getOAuth2ErrorCode() { + return "unauthorized_client"; + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/UnauthorizedUserException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/UnauthorizedUserException.java new file mode 100644 index 000000000..92562166e --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/UnauthorizedUserException.java @@ -0,0 +1,32 @@ +package org.springframework.security.oauth2.common.exceptions; + +/** + * Exception thrown when a user was unable to authenticate. + * + *

+ * + * @author Dave Syer + */ +@SuppressWarnings("serial") +public class UnauthorizedUserException extends OAuth2Exception { + + public UnauthorizedUserException(String msg, Throwable t) { + super(msg, t); + } + + public UnauthorizedUserException(String msg) { + super(msg); + } + + @Override + public int getHttpErrorCode() { + // The spec says this can be unauthorized + return 401; + } + + @Override + public String getOAuth2ErrorCode() { + // Not in the spec + return "unauthorized_user"; + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/UnsupportedGrantTypeException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/UnsupportedGrantTypeException.java new file mode 100644 index 000000000..af30ef620 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/UnsupportedGrantTypeException.java @@ -0,0 +1,23 @@ +package org.springframework.security.oauth2.common.exceptions; + +/** + *

+ * + * @author Ryan Heaton + */ +@SuppressWarnings("serial") +public class UnsupportedGrantTypeException extends OAuth2Exception { + + public UnsupportedGrantTypeException(String msg, Throwable t) { + super(msg, t); + } + + public UnsupportedGrantTypeException(String msg) { + super(msg); + } + + @Override + public String getOAuth2ErrorCode() { + return "unsupported_grant_type"; + } +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/UnsupportedResponseTypeException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/UnsupportedResponseTypeException.java new file mode 100644 index 000000000..d427ae7b1 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/UnsupportedResponseTypeException.java @@ -0,0 +1,23 @@ +package org.springframework.security.oauth2.common.exceptions; + +/** + *

+ * + * @author Ryan Heaton + */ +@SuppressWarnings("serial") +public class UnsupportedResponseTypeException extends OAuth2Exception { + + public UnsupportedResponseTypeException(String msg, Throwable t) { + super(msg, t); + } + + public UnsupportedResponseTypeException(String msg) { + super(msg); + } + + @Override + public String getOAuth2ErrorCode() { + return "unsupported_response_type"; + } +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/common/exceptions/UserDeniedAuthorizationException.java b/src/main/java/org/springframework/security/oauth2/common/exceptions/UserDeniedAuthorizationException.java new file mode 100644 index 000000000..07d4abbf1 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/exceptions/UserDeniedAuthorizationException.java @@ -0,0 +1,24 @@ +package org.springframework.security.oauth2.common.exceptions; + +/** + *

+ * + * @author Ryan Heaton + */ +@SuppressWarnings("serial") +public class UserDeniedAuthorizationException extends OAuth2Exception { + + public UserDeniedAuthorizationException(String msg, Throwable t) { + super(msg, t); + } + + public UserDeniedAuthorizationException(String msg) { + super(msg); + } + + @Override + public String getOAuth2ErrorCode() { + return "access_denied"; + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/common/util/DefaultSerializationStrategy.java b/src/main/java/org/springframework/security/oauth2/common/util/DefaultSerializationStrategy.java new file mode 100644 index 000000000..c6c4bb1af --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/util/DefaultSerializationStrategy.java @@ -0,0 +1,90 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.common.util; + +import org.springframework.core.ConfigurableObjectInputStream; + +import java.io.*; + +/** + * The default {@link SerializationStrategy} which uses the built-in Java serialization mechanism. + *

+ * Note that this class should not be used if data for deserialization comes from an untrusted source. + * Instead, please use {@link WhitelistedSerializationStrategy} with a list of allowed classes for deserialization. + * + *

+ * + * @author Artem Smotrakov + * @since 2.4 + */ +public class DefaultSerializationStrategy implements SerializationStrategy { + + public byte[] serialize(Object state) { + ObjectOutputStream oos = null; + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(512); + oos = new ObjectOutputStream(bos); + oos.writeObject(state); + oos.flush(); + return bos.toByteArray(); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } finally { + if (oos != null) { + try { + oos.close(); + } catch (IOException e) { + // eat it + } + } + } + } + + public T deserialize(byte[] byteArray) { + ObjectInputStream oip = null; + try { + oip = createObjectInputStream(byteArray); + @SuppressWarnings("unchecked") + T result = (T) oip.readObject(); + return result; + } catch (IOException e) { + throw new IllegalArgumentException(e); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException(e); + } finally { + if (oip != null) { + try { + oip.close(); + } catch (IOException e) { + // eat it + } + } + } + } + + /** + * Creates an {@link ObjectInputStream} for deserialization. + * + * @param byteArray Data to be deserialized. + * @return An instance of {@link ObjectInputStream} which should be used for deserialization. + * @throws IOException If something went wrong. + */ + protected ObjectInputStream createObjectInputStream(byte[] byteArray) throws IOException { + return new ConfigurableObjectInputStream(new ByteArrayInputStream(byteArray), + Thread.currentThread().getContextClassLoader()); + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/util/Jackson2JsonParser.java b/src/main/java/org/springframework/security/oauth2/common/util/Jackson2JsonParser.java new file mode 100644 index 000000000..9b4fce3c3 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/util/Jackson2JsonParser.java @@ -0,0 +1,53 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springframework.security.oauth2.common.util; + +import java.util.Map; + +import com.fasterxml.jackson.databind.ObjectMapper; + + + +/** + *

+ * + * @author Dave Syer + * + */ +public class Jackson2JsonParser implements JsonParser { + + private ObjectMapper mapper = new ObjectMapper(); + + @SuppressWarnings("unchecked") + @Override + public Map parseMap(String json) { + try { + return mapper.readValue(json, Map.class); + } + catch (Exception e) { + throw new IllegalArgumentException("Cannot parse json", e); + } + } + + @Override + public String formatMap(Map map) { + try { + return mapper.writeValueAsString(map); + } + catch (Exception e) { + throw new IllegalArgumentException("Cannot format json", e); + } + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/common/util/JdbcListFactory.java b/src/main/java/org/springframework/security/oauth2/common/util/JdbcListFactory.java new file mode 100644 index 000000000..ca5357472 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/util/JdbcListFactory.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.common.util; + +import java.util.List; +import java.util.Map; + +import org.springframework.jdbc.core.RowMapper; + +/** + *

+ * + * @author Dave Syer + * + */ +public interface JdbcListFactory { + + /** + * @param sql + * @param parameters + * @return a list of {@link T} + */ + List getList(String sql, Map parameters, RowMapper rowMapper); + +} diff --git a/src/main/java/org/springframework/security/oauth2/common/util/JsonDateDeserializer.java b/src/main/java/org/springframework/security/oauth2/common/util/JsonDateDeserializer.java new file mode 100644 index 000000000..d1c855b59 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/util/JsonDateDeserializer.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.common.util; + +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +/** + * JSON deserializer for Jackson to handle regular date instances as timestamps in ISO format. + * + *

+ * + * @author Dave Syer + * + */ +public class JsonDateDeserializer extends JsonDeserializer { + + private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + + @Override + public Date deserialize(com.fasterxml.jackson.core.JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException { + try { + synchronized (dateFormat) { + return dateFormat.parse(parser.getText()); + } + } + catch (ParseException e) { + throw new JsonParseException("Could not parse date", parser.getCurrentLocation(), e); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/common/util/JsonDateSerializer.java b/src/main/java/org/springframework/security/oauth2/common/util/JsonDateSerializer.java new file mode 100644 index 000000000..a7de32555 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/util/JsonDateSerializer.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.common.util; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +/** + * JSON serializer for Jackson to handle regular date instances as timestamps in ISO format. + * + *

+ * + * @author Dave Syer + * + */ +public class JsonDateSerializer extends JsonSerializer { + + private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + + @Override + public void serialize(Date date, JsonGenerator generator, SerializerProvider provider) throws IOException, + JsonProcessingException { + synchronized (dateFormat) { + String formatted = dateFormat.format(date); + generator.writeString(formatted); + } + } + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/common/util/JsonParser.java b/src/main/java/org/springframework/security/oauth2/common/util/JsonParser.java new file mode 100644 index 000000000..2a51027a0 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/util/JsonParser.java @@ -0,0 +1,40 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springframework.security.oauth2.common.util; + +import java.util.Map; + +/** + *

+ * + * @author Dave Syer + * + */ +public interface JsonParser { + + /** + * Parse the specified JSON string into a Map. + * @param json the JSON to parse + * @return the parsed JSON as a map + */ + Map parseMap(String json); + + /** + * Convert the Map to JSON + * @param map a map to format + * @return a JSON representation of the map + */ + String formatMap(Map map); + +} diff --git a/src/main/java/org/springframework/security/oauth2/common/util/JsonParserFactory.java b/src/main/java/org/springframework/security/oauth2/common/util/JsonParserFactory.java new file mode 100644 index 000000000..f59c50443 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/util/JsonParserFactory.java @@ -0,0 +1,33 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springframework.security.oauth2.common.util; + +import org.springframework.util.ClassUtils; + +/** + *

+ * + * @author Dave Syer + * + */ +public class JsonParserFactory { + + public static JsonParser create() { + if (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", null)) { + return new Jackson2JsonParser(); + } + throw new IllegalStateException("No Jackson 2 parser found. Please add Jackson 2 to your classpath."); + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/common/util/OAuth2Utils.java b/src/main/java/org/springframework/security/oauth2/common/util/OAuth2Utils.java new file mode 100644 index 000000000..d38aa7b1e --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/util/OAuth2Utils.java @@ -0,0 +1,133 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.oauth2.common.util; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; + +import org.springframework.util.StringUtils; + +/** + *

+ * + * @author Ryan Heaton + * @author Dave Syer + */ +public abstract class OAuth2Utils { + + /** + * Constant to use while parsing and formatting parameter maps for OAuth2 requests + */ + public static final String CLIENT_ID = "client_id"; + + /** + * Constant to use while parsing and formatting parameter maps for OAuth2 requests + */ + public static final String STATE = "state"; + + /** + * Constant to use while parsing and formatting parameter maps for OAuth2 requests + */ + public static final String SCOPE = "scope"; + + /** + * Constant to use while parsing and formatting parameter maps for OAuth2 requests + */ + public static final String REDIRECT_URI = "redirect_uri"; + + /** + * Constant to use while parsing and formatting parameter maps for OAuth2 requests + */ + public static final String RESPONSE_TYPE = "response_type"; + + /** + * Constant to use while parsing and formatting parameter maps for OAuth2 requests + */ + public static final String USER_OAUTH_APPROVAL = "user_oauth_approval"; + + /** + * Constant to use as a prefix for scope approval + */ + public static final String SCOPE_PREFIX = "scope."; + + /** + * Constant to use while parsing and formatting parameter maps for OAuth2 requests + */ + public static final String GRANT_TYPE = "grant_type"; + + /** + * Parses a string parameter value into a set of strings. + * + * @param values The values of the set. + * @return The set. + */ + public static Set parseParameterList(String values) { + Set result = new TreeSet(); + if (values != null && values.trim().length() > 0) { + // the spec says the scope is separated by spaces + String[] tokens = values.split("[\\s+]"); + result.addAll(Arrays.asList(tokens)); + } + return result; + } + + /** + * Formats a set of string values into a format appropriate for sending as a single-valued form value. + * + * @param value The value of the parameter. + * @return The value formatted for form submission etc, or null if the input is empty + */ + public static String formatParameterList(Collection value) { + return value == null ? null : StringUtils.collectionToDelimitedString(value, " "); + } + + /** + * Extract a map from a query string. + * + * @param query a query (or fragment) string from a URI + * @return a Map of the values in the query + */ + public static Map extractMap(String query) { + Map map = new HashMap(); + Properties properties = StringUtils.splitArrayElementsIntoProperties( + StringUtils.delimitedListToStringArray(query, "&"), "="); + if (properties != null) { + for (Object key : properties.keySet()) { + map.put(key.toString(), properties.get(key).toString()); + } + } + return map; + } + + /** + * Compare 2 sets and check that one contains all members of the other. + * + * @param target set of strings to check + * @param members the members to compare to + * @return true if all members are in the target + */ + public static boolean containsAll(Set target, Set members) { + target = new HashSet(target); + target.retainAll(members); + return target.size() == members.size(); + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/util/ProxyCreator.java b/src/main/java/org/springframework/security/oauth2/common/util/ProxyCreator.java new file mode 100644 index 000000000..82fa20c49 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/util/ProxyCreator.java @@ -0,0 +1,73 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springframework.security.oauth2.common.util; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import org.springframework.beans.factory.ObjectFactory; + +/** + *

+ * + * @author Dave Syer + * + */ +public class ProxyCreator { + + @SuppressWarnings("unchecked") + public static T getProxy(Class type, ObjectFactory factory) { + return (T) Proxy.newProxyInstance(ProxyCreator.class.getClassLoader(), new Class[] { type }, + new LazyInvocationHandler(factory)); + } + + private static class LazyInvocationHandler implements InvocationHandler { + + private T target; + + private ObjectFactory factory; + + public LazyInvocationHandler(ObjectFactory factory) { + this.factory = factory; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + // Invocation on interface coming in... + + if (method.getName().equals("equals")) { + return (proxy == args[0]); + } + else if (method.getName().equals("hashCode")) { + return System.identityHashCode(proxy); + } + try { + return method.invoke(getTarget(method), args); + } + catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + private Object getTarget(Method method) { + if (target == null) { + target = factory.getObject(); + } + return target; + } + + } +} diff --git a/src/main/java/org/springframework/security/oauth2/common/util/RandomValueStringGenerator.java b/src/main/java/org/springframework/security/oauth2/common/util/RandomValueStringGenerator.java new file mode 100644 index 000000000..76f3a8ecd --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/util/RandomValueStringGenerator.java @@ -0,0 +1,97 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.oauth2.common.util; + +import java.security.SecureRandom; +import java.util.Random; + +/** + * Utility that generates a random-value ASCII string. + * + *

+ * + * @author Ryan Heaton + * @author Dave Syer + */ +public class RandomValueStringGenerator { + + private static final char[] DEFAULT_CODEC = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_" + .toCharArray(); + + private Random random = new SecureRandom(); + + private int length; + + /** + * Create a generator with the default length (6). + */ + public RandomValueStringGenerator() { + this(6); + } + + /** + * Create a generator of random strings of the length provided + * + * @param length the length of the strings generated + */ + public RandomValueStringGenerator(int length) { + this.length = length; + } + + public String generate() { + byte[] verifierBytes = new byte[length]; + random.nextBytes(verifierBytes); + return getAuthorizationCodeString(verifierBytes); + } + + /** + * Convert these random bytes to a verifier string. The length of the byte array can be + * {@link #setLength(int) configured}. The default implementation mods the bytes to fit into the + * ASCII letters 1-9, A-Z, a-z, -_ . + * + * @param verifierBytes The bytes. + * @return The string. + */ + protected String getAuthorizationCodeString(byte[] verifierBytes) { + char[] chars = new char[verifierBytes.length]; + for (int i = 0; i < verifierBytes.length; i++) { + chars[i] = DEFAULT_CODEC[((verifierBytes[i] & 0xFF) % DEFAULT_CODEC.length)]; + } + return new String(chars); + } + + /** + * The random value generator used to create token secrets. + * + * @param random The random value generator used to create token secrets. + */ + public void setRandom(Random random) { + this.random = random; + } + + /** + * The length of string to generate. A length less than or equal to 0 will result in an {@code IllegalArgumentException}. + * + * @param length the length to set + */ + public void setLength(int length) { + if (length <= 0) { + throw new IllegalArgumentException("length must be greater than 0"); + } + this.length = length; + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/common/util/SerializationStrategy.java b/src/main/java/org/springframework/security/oauth2/common/util/SerializationStrategy.java new file mode 100644 index 000000000..ee53edf0c --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/util/SerializationStrategy.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.common.util; + +/** + * Defines how objects are serialized and deserialized. + * + *

+ * + * @author Artem Smotrakov + * @since 2.4 + */ +public interface SerializationStrategy { + + /** + * Serializes an object. + * + * @param object The object to be serialized. + * @return A byte array. + */ + byte[] serialize(Object object); + + /** + * Deserializes an object from a byte array. + * + * @param byteArray The byte array. + * @param The type of the object. + * @return The deserialized object. + */ + T deserialize(byte[] byteArray); + +} diff --git a/src/main/java/org/springframework/security/oauth2/common/util/SerializationUtils.java b/src/main/java/org/springframework/security/oauth2/common/util/SerializationUtils.java new file mode 100644 index 000000000..079c20a28 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/util/SerializationUtils.java @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.common.util; + +import org.springframework.core.io.support.SpringFactoriesLoader; +import org.springframework.util.Assert; + +import java.util.List; + +/** + * This is a helper class for serializing and deserializing objects with a {@link SerializationStrategy}. + * The class looks for the strategy in {@code META-INF/spring.factories}, + * or the strategy can also be set by calling {@link #setSerializationStrategy(SerializationStrategy)}. + * If no strategy is specified, the default is {@link DefaultSerializationStrategy}. + *

+ * Note that the default strategy allows deserializing arbitrary classes which may result in security problems + * if data comes from an untrusted source. To prevent possible issues, use {@link WhitelistedSerializationStrategy} + * with a list of allowed classes for deserialization. + * + *

+ * + */ +public class SerializationUtils { + + private static SerializationStrategy strategy = new DefaultSerializationStrategy(); + + static { + List strategies = SpringFactoriesLoader.loadFactories( + SerializationStrategy.class, SerializationUtils.class.getClassLoader()); + if (strategies.size() > 1) { + throw new IllegalArgumentException( + "Too many serialization strategies in META-INF/spring.factories"); + } + if (strategies.size() == 1) { + strategy = strategies.get(0); + } + } + + /** + * @return The current serialization strategy. + */ + public static SerializationStrategy getSerializationStrategy() { + return strategy; + } + + /** + * Sets a new serialization strategy. + * + * @param serializationStrategy The serialization strategy. + */ + public static void setSerializationStrategy(SerializationStrategy serializationStrategy) { + Assert.notNull(serializationStrategy, "serializationStrategy cannot be null"); + strategy = serializationStrategy; + } + + public static byte[] serialize(Object object) { + return strategy.serialize(object); + } + + public static T deserialize(byte[] byteArray) { + return strategy.deserialize(byteArray); + } + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/common/util/WhitelistedSerializationStrategy.java b/src/main/java/org/springframework/security/oauth2/common/util/WhitelistedSerializationStrategy.java new file mode 100644 index 000000000..abd7ead5d --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/common/util/WhitelistedSerializationStrategy.java @@ -0,0 +1,145 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.common.util; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.springframework.util.ClassUtils; + +/** + * A {@link SerializationStrategy} which uses a whitelist of allowed classes for deserialization. + * + *

+ * + * @author Artem Smotrakov + * @since 2.4 + */ +public class WhitelistedSerializationStrategy extends DefaultSerializationStrategy { + + /** + * A list of classes which are allowed to deserialize by default. + */ + private static final List DEFAULT_ALLOWED_CLASSES; + + static { + List classes = new ArrayList(); + classes.add("java.lang."); + classes.add("java.util."); + classes.add("org.springframework.security."); + DEFAULT_ALLOWED_CLASSES = Collections.unmodifiableList(classes); + } + + /** + * A list of classes which are allowed to deserialize. + */ + private final List allowedClasses; + + /** + * Initializes {@link WhitelistedSerializationStrategy} with the list of classes + * which are allowed to deserialize by default. + */ + public WhitelistedSerializationStrategy() { + this(DEFAULT_ALLOWED_CLASSES); + } + + /** + * Initializes {@link WhitelistedSerializationStrategy} with specified allowed classes. + * + * @param allowedClasses The allowed classes for deserialization. + */ + public WhitelistedSerializationStrategy(List allowedClasses) { + this.allowedClasses = Collections.unmodifiableList(allowedClasses); + } + + protected ObjectInputStream createObjectInputStream(byte[] byteArray) throws IOException { + return new WhitelistedObjectInputStream(new ByteArrayInputStream(byteArray), + Thread.currentThread().getContextClassLoader(), allowedClasses); + } + + /** + * Special ObjectInputStream subclass that checks if classes are allowed to deserialize. The class + * should be configured with a whitelist of only allowed (safe) classes to deserialize. + */ + private static class WhitelistedObjectInputStream extends ObjectInputStream { + + /** + * The list of classes which are allowed for deserialization. + */ + private final List allowedClasses; + + /** + * The class loader to use for loading local classes. + */ + private final ClassLoader classLoader; + + /** + * Create a new WhitelistedObjectInputStream for the given InputStream, class loader and + * allowed class names. + * + * @param in The InputStream to read from. + * @param classLoader The ClassLoader to use for loading local classes. + * @param allowedClasses The list of allowed classes for deserialization. + * @throws IOException If something went wrong. + */ + private WhitelistedObjectInputStream(InputStream in, ClassLoader classLoader, List allowedClasses) + throws IOException { + super(in); + this.classLoader = classLoader; + this.allowedClasses = Collections.unmodifiableList(allowedClasses); + } + + /** + * Resolve the class only if it's allowed to deserialize. + * + * @see ObjectInputStream#resolveClass(ObjectStreamClass) + */ + @Override + protected Class resolveClass(ObjectStreamClass classDesc) + throws IOException, ClassNotFoundException { + if (isProhibited(classDesc.getName())) { + throw new NotSerializableException("Not allowed to deserialize " + classDesc.getName()); + } + if (this.classLoader != null) { + return ClassUtils.forName(classDesc.getName(), this.classLoader); + } + return super.resolveClass(classDesc); + } + + /** + * Check if the class is allowed to be deserialized. + * + * @param className The class to check. + * @return True if the class is not allowed to be deserialized, false otherwise. + */ + private boolean isProhibited(String className) { + for (String allowedClass : this.allowedClasses) { + if (className.startsWith(allowedClass)) { + return false; + } + } + return true; + } + } +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/AuthorizationRequest.java b/src/main/java/org/springframework/security/oauth2/provider/AuthorizationRequest.java new file mode 100644 index 000000000..9f9a5f380 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/AuthorizationRequest.java @@ -0,0 +1,302 @@ +package org.springframework.security.oauth2.provider; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.oauth2.common.util.OAuth2Utils; +import org.springframework.web.bind.annotation.SessionAttributes; + +/** + * A request for authorization by an OAuth 2 Client, normally received and + * processed by the AuthorizationEndpoint. This class is meant to be manipulated + * throughout the authorization process, and is therefore treated as ephemeral + * and not to be stored long term. For long term storage, use the read-only + * {@link OAuth2Request} class. + * + * HTTP request parameters are stored in the parameters map, and any processing + * the server makes throughout the lifecycle of a request are stored on + * individual properties. The original request parameters will remain available + * through the parameters map. For convenience, constants are defined in order + * to get at those original values. However, the parameters map is unmodifiable + * so that processing cannot drop the original values. + * + * This class is {@link Serializable} in order to support storage of the + * authorization request as a {@link SessionAttributes} member while the end + * user through the authorization process (which may span several page + * requests). + * + *

+ * + * @author Ryan Heaton + * @author Dave Syer + * @author Amanda Anganes + */ +@SuppressWarnings("serial") +public class AuthorizationRequest extends BaseRequest implements Serializable { + + /** + * Map to hold the original, unchanged parameter set submitted by a user to + * signal approval of the token grant approval. Once set this should not be + * modified. + */ + private Map approvalParameters = Collections.unmodifiableMap(new HashMap()); + + /** + * The value of the "state" parameter sent by the client in the request, if + * sent by the client. As this must be echoed back to the client unchanged, + * it should not be modified by any processing classes. + */ + private String state; + + /** + * Resolved requested response types initialized (by the + * OAuth2RequestFactory) with the response types originally requested. + */ + private Set responseTypes = new HashSet(); + + /** + * Resolved resource IDs. This set may change during request processing. + */ + private Set resourceIds = new HashSet(); + + /** + * Resolved granted authorities for this request. May change during request + * processing. + */ + private Collection authorities = new HashSet(); + + /** + * Whether the request has been approved by the end user (or other process). + * This will be altered by the User Approval Endpoint and/or the + * UserApprovalHandler as appropriate. + */ + private boolean approved = false; + + /** + * The resolved redirect URI of this request. A URI may be present in the + * original request, in the authorizationParameters, or it may not be + * provided, in which case it will be defaulted (by processing classes) to + * the Client's default registered value. + */ + private String redirectUri; + + /** + * Extension point for custom processing classes which may wish to store + * additional information about the OAuth2 request. Since this class will + * create a serializable OAuth2Request, all members of this extension map + * must be serializable. + */ + private Map extensions = new HashMap(); + + /** + * Default constructor. + */ + public AuthorizationRequest() { + } + + /** + * Full constructor. + */ + public AuthorizationRequest(Map authorizationParameters, Map approvalParameters, String clientId, Set scope, Set resourceIds, Collection authorities, boolean approved, String state, String redirectUri, + Set responseTypes) { + setClientId(clientId); + setRequestParameters(authorizationParameters); // in case we need to + // wrap the collection + setScope(scope); // in case we need to parse + if (resourceIds != null) { + this.resourceIds = new HashSet(resourceIds); + } + if (authorities != null) { + this.authorities = new HashSet(authorities); + } + this.approved = approved; + this.resourceIds = resourceIds; + this.redirectUri = redirectUri; + if (responseTypes != null) { + this.responseTypes = responseTypes; + } + this.state = state; + } + + public OAuth2Request createOAuth2Request() { + return new OAuth2Request(getRequestParameters(), getClientId(), getAuthorities(), isApproved(), getScope(), getResourceIds(), getRedirectUri(), getResponseTypes(), getExtensions()); + } + + /** + * Convenience constructor for unit tests, where client ID and scope are + * often the only needed fields. + * + * @param clientId + * @param scopes + */ + public AuthorizationRequest(String clientId, Collection scopes) { + setClientId(clientId); + setScope(scopes); // in case we need to parse + } + + /** + * Convenience method to set resourceIds and authorities on this request by + * inheriting from a ClientDetails object. + * + * @param clientDetails + */ + public void setResourceIdsAndAuthoritiesFromClientDetails(ClientDetails clientDetails) { + setResourceIds(clientDetails.getResourceIds()); + setAuthorities(clientDetails.getAuthorities()); + } + + public Map getApprovalParameters() { + return approvalParameters; + } + + public void setApprovalParameters(Map approvalParameters) { + this.approvalParameters = approvalParameters; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public Set getResponseTypes() { + return responseTypes; + } + + public void setResponseTypes(Set responseTypes) { + this.responseTypes = responseTypes; + } + + public void setRedirectUri(String redirectUri) { + this.redirectUri = redirectUri; + } + + public void setApproved(boolean approved) { + this.approved = approved; + } + + public void setAuthorities(Collection authorities) { + if (authorities != null) { + this.authorities = new HashSet(authorities); + } + } + + /** + * @return the extensions + */ + public Map getExtensions() { + return extensions; + } + + public void setExtensions(Map extensions) { + this.extensions = extensions; + } + + public void setResourceIds(Set resourceIds) { + this.resourceIds = resourceIds; + } + + public void setClientId(String clientId) { + super.setClientId(clientId); + } + + /** + * Set the scope value. If the collection contains only a single scope + * value, this method will parse that value into a collection using + * {@link OAuth2Utils#parseParameterList}. + * + * @see TokenRequest#setScope + * + * @param scope + */ + public void setScope(Collection scope) { + super.setScope(scope); + } + + /** + * Set the Request Parameters on this authorization request, which represent + * the original request parameters and should never be changed during + * processing. The map passed in is wrapped in an unmodifiable map instance. + * + * @see TokenRequest#setRequestParameters + * + * @param requestParameters + */ + public void setRequestParameters(Map requestParameters) { + super.setRequestParameters(requestParameters); + } + + /** + * @return the resourceIds + */ + public Set getResourceIds() { + return resourceIds; + } + + /** + * @return the authorities + */ + public Collection getAuthorities() { + return authorities; + } + + /** + * @return the approved + */ + public boolean isApproved() { + return approved; + } + + /** + * @return the redirectUri + */ + public String getRedirectUri() { + return redirectUri; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((approvalParameters == null) ? 0 : approvalParameters.hashCode()); + result = prime * result + ((responseTypes == null) ? 0 : responseTypes.hashCode()); + result = prime * result + ((state == null) ? 0 : state.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + AuthorizationRequest other = (AuthorizationRequest) obj; + if (approvalParameters == null) { + if (other.approvalParameters != null) + return false; + } else if (!approvalParameters.equals(other.approvalParameters)) + return false; + if (responseTypes == null) { + if (other.responseTypes != null) + return false; + } else if (!responseTypes.equals(other.responseTypes)) + return false; + if (state == null) { + if (other.state != null) + return false; + } else if (!state.equals(other.state)) + return false; + return true; + } + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/provider/BaseRequest.java b/src/main/java/org/springframework/security/oauth2/provider/BaseRequest.java new file mode 100644 index 000000000..47e869cca --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/BaseRequest.java @@ -0,0 +1,162 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.provider; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import org.springframework.security.oauth2.common.util.OAuth2Utils; + +/** + * + * A base class for the three "*Request" classes used in processing OAuth 2 + * authorizations. This class should never be used directly, + * and it should never be used as the type for a local or other + * variable. + * + * @author Dave Syer + * + */ +@SuppressWarnings("serial") +abstract class BaseRequest implements Serializable { + + /** + * Resolved client ID. This may be present in the original request + * parameters, or in some cases may be inferred by a processing class and + * inserted here. + */ + private String clientId; + + /** + * Resolved scope set, initialized (by the OAuth2RequestFactory) with the + * scopes originally requested. Further processing and user interaction may + * alter the set of scopes that is finally granted and stored when the + * request processing is complete. + */ + private Set scope = new HashSet(); + + /** + * Map of parameters passed in to the Authorization Endpoint or Token + * Endpoint, preserved unchanged from the original request. This map should + * not be modified after initialization. In general, classes should not + * retrieve values from this map directly, and should instead use the + * individual members on this class. + * + * The OAuth2RequestFactory is responsible for initializing all members of + * this class, usually by parsing the values inside the requestParmaeters + * map. + * + */ + private Map requestParameters = Collections + .unmodifiableMap(new HashMap()); + + public String getClientId() { + return clientId; + } + + public Set getScope() { + return scope; + } + + /** + * Warning: most clients should use the individual properties of this class, + * such as {{@link #getScope()} or { {@link #getClientId()}, rather than + * retrieving values from this map. + * + * @return the original, unchanged set of request parameters + */ + public Map getRequestParameters() { + return requestParameters; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((clientId == null) ? 0 : clientId.hashCode()); + result = prime + * result + + ((requestParameters == null) ? 0 : requestParameters + .hashCode()); + result = prime * result + ((scope == null) ? 0 : scope.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + BaseRequest other = (BaseRequest) obj; + if (clientId == null) { + if (other.clientId != null) + return false; + } else if (!clientId.equals(other.clientId)) + return false; + if (requestParameters == null) { + if (other.requestParameters != null) + return false; + } else if (!requestParameters.equals(other.requestParameters)) + return false; + if (scope == null) { + if (other.scope != null) + return false; + } else if (!scope.equals(other.scope)) + return false; + return true; + } + + protected void setScope(Collection scope) { + if (scope != null && scope.size() == 1) { + String value = scope.iterator().next(); + /* + * This is really an error, but it can catch out unsuspecting users + * and it's easy to fix. It happens when an AuthorizationRequest + * gets bound accidentally from request parameters using + * @ModelAttribute. + */ + if (value.contains(" ") || value.contains(",")) { + scope = OAuth2Utils.parseParameterList(value); + } + } + this.scope = Collections + .unmodifiableSet(scope == null ? new LinkedHashSet() + : new LinkedHashSet(scope)); + } + + protected void setRequestParameters(Map requestParameters) { + if (requestParameters != null) { + this.requestParameters = Collections + .unmodifiableMap(new HashMap(requestParameters)); + } + } + + protected void setClientId(String clientId) { + this.clientId = clientId; + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/ClientAlreadyExistsException.java b/src/main/java/org/springframework/security/oauth2/provider/ClientAlreadyExistsException.java new file mode 100644 index 000000000..4cd6c7574 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/ClientAlreadyExistsException.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.oauth2.provider; + +/** + * Exception indicating that a client registration already exists (e.g. if someone tries to create a duplicate). + * + *

+ * + * @author Dave Syer + * + */ +@SuppressWarnings("serial") +public class ClientAlreadyExistsException extends ClientRegistrationException { + + public ClientAlreadyExistsException(String msg) { + super(msg); + } + + public ClientAlreadyExistsException(String msg, Throwable cause) { + super(msg, cause); + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/ClientDetails.java b/src/main/java/org/springframework/security/oauth2/provider/ClientDetails.java new file mode 100644 index 000000000..e13c0d165 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/ClientDetails.java @@ -0,0 +1,118 @@ +package org.springframework.security.oauth2.provider; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import org.springframework.security.core.GrantedAuthority; + +/** + * Client details for OAuth 2 + * + *

+ * + * @author Ryan Heaton + */ +public interface ClientDetails extends Serializable { + + /** + * The client id. + * + * @return The client id. + */ + String getClientId(); + + /** + * The resources that this client can access. Can be ignored by callers if empty. + * + * @return The resources of this client. + */ + Set getResourceIds(); + + /** + * Whether a secret is required to authenticate this client. + * + * @return Whether a secret is required to authenticate this client. + */ + boolean isSecretRequired(); + + /** + * The client secret. Ignored if the {@link #isSecretRequired() secret isn't required}. + * + * @return The client secret. + */ + String getClientSecret(); + + /** + * Whether this client is limited to a specific scope. If false, the scope of the authentication request will be + * ignored. + * + * @return Whether this client is limited to a specific scope. + */ + boolean isScoped(); + + /** + * The scope of this client. Empty if the client isn't scoped. + * + * @return The scope of this client. + */ + Set getScope(); + + /** + * The grant types for which this client is authorized. + * + * @return The grant types for which this client is authorized. + */ + Set getAuthorizedGrantTypes(); + + /** + * The pre-defined redirect URI for this client to use during the "authorization_code" access grant. See OAuth spec, + * section 4.1.1. + * + * @return The pre-defined redirect URI for this client. + */ + Set getRegisteredRedirectUri(); + + /** + * Returns the authorities that are granted to the OAuth client. Cannot return null. + * Note that these are NOT the authorities that are granted to the user with an authorized access token. + * Instead, these authorities are inherent to the client itself. + * + * @return the authorities (never null) + */ + Collection getAuthorities(); + + /** + * The access token validity period for this client. Null if not set explicitly (implementations might use that fact + * to provide a default value for instance). + * + * @return the access token validity period + */ + Integer getAccessTokenValiditySeconds(); + + /** + * The refresh token validity period for this client. Null for default value set by token service, and + * zero or negative for non-expiring tokens. + * + * @return the refresh token validity period + */ + Integer getRefreshTokenValiditySeconds(); + + /** + * Test whether client needs user approval for a particular scope. + * + * @param scope the scope to consider + * @return true if this client does not need user approval + */ + boolean isAutoApprove(String scope); + + /** + * Additional information for this client, not needed by the vanilla OAuth protocol but might be useful, for example, + * for storing descriptive information. + * + * @return a map of additional information + */ + Map getAdditionalInformation(); + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/ClientDetailsService.java b/src/main/java/org/springframework/security/oauth2/provider/ClientDetailsService.java new file mode 100644 index 000000000..b5b8d2c7e --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/ClientDetailsService.java @@ -0,0 +1,38 @@ +/* + * Copyright 2008 Web Cohesion + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.provider; + + +/** + * A service that provides the details about an OAuth2 client. + * + *

+ * + * @author Ryan Heaton + */ +public interface ClientDetailsService { + + /** + * Load a client by the client id. This method must not return null. + * + * @param clientId The client id. + * @return The client details (never null). + * @throws ClientRegistrationException If the client account is locked, expired, disabled, or invalid for any other reason. + */ + ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException; + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/provider/ClientRegistrationException.java b/src/main/java/org/springframework/security/oauth2/provider/ClientRegistrationException.java new file mode 100644 index 000000000..3a4a4248e --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/ClientRegistrationException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.oauth2.provider; + +/** + *

+ * + * @author Dave Syer + * + */ +@SuppressWarnings("serial") +public class ClientRegistrationException extends RuntimeException { + + public ClientRegistrationException(String msg) { + super(msg); + } + + public ClientRegistrationException(String msg, Throwable cause) { + super(msg, cause); + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/ClientRegistrationService.java b/src/main/java/org/springframework/security/oauth2/provider/ClientRegistrationService.java new file mode 100644 index 000000000..dff56e58b --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/ClientRegistrationService.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.oauth2.provider; + +import java.util.List; + +/** + * Interface for client registration, handling add, update and remove of {@link ClientDetails} from an Authorization + * Server. + * + *

+ * + * @author Dave Syer + * + */ +public interface ClientRegistrationService { + + void addClientDetails(ClientDetails clientDetails) throws ClientAlreadyExistsException; + + void updateClientDetails(ClientDetails clientDetails) throws NoSuchClientException; + + void updateClientSecret(String clientId, String secret) throws NoSuchClientException; + + void removeClientDetails(String clientId) throws NoSuchClientException; + + List listClientDetails(); + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/CompositeTokenGranter.java b/src/main/java/org/springframework/security/oauth2/provider/CompositeTokenGranter.java new file mode 100644 index 000000000..7ab15336b --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/CompositeTokenGranter.java @@ -0,0 +1,55 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.provider; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.security.oauth2.common.OAuth2AccessToken; + +/** + *

+ * + * @author Dave Syer + * + */ +public class CompositeTokenGranter implements TokenGranter { + + private final List tokenGranters; + + public CompositeTokenGranter(List tokenGranters) { + this.tokenGranters = new ArrayList(tokenGranters); + } + + public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) { + for (TokenGranter granter : tokenGranters) { + OAuth2AccessToken grant = granter.grant(grantType, tokenRequest); + if (grant!=null) { + return grant; + } + } + return null; + } + + public void addTokenGranter(TokenGranter tokenGranter) { + if (tokenGranter == null) { + throw new IllegalArgumentException("Token granter is null"); + } + tokenGranters.add(tokenGranter); + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/DefaultSecurityContextAccessor.java b/src/main/java/org/springframework/security/oauth2/provider/DefaultSecurityContextAccessor.java new file mode 100644 index 000000000..fe76967d8 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/DefaultSecurityContextAccessor.java @@ -0,0 +1,61 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springframework.security.oauth2.provider; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; + +/** + * Strategy for accessing useful information about the current security context. + * + *

+ * + * @author Dave Syer + * + */ +public class DefaultSecurityContextAccessor implements SecurityContextAccessor { + + @Override + public boolean isUser() { + Authentication authentication = getUserAuthentication(); + return authentication != null; + } + + @Override + public Set getAuthorities() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null) { + return Collections.emptySet(); + } + return Collections.unmodifiableSet(new HashSet(authentication.getAuthorities())); + } + + private Authentication getUserAuthentication() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null) { + return null; + } + if (authentication instanceof OAuth2Authentication) { + OAuth2Authentication oauth = (OAuth2Authentication) authentication; + return oauth.getUserAuthentication(); + } + return authentication; + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/NoSuchClientException.java b/src/main/java/org/springframework/security/oauth2/provider/NoSuchClientException.java new file mode 100644 index 000000000..5a1468896 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/NoSuchClientException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.oauth2.provider; + +/** + *

+ * + * @author Dave Syer + * + */ +@SuppressWarnings("serial") +public class NoSuchClientException extends ClientRegistrationException { + + public NoSuchClientException(String msg) { + super(msg); + } + + public NoSuchClientException(String msg, Throwable cause) { + super(msg, cause); + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/OAuth2Authentication.java b/src/main/java/org/springframework/security/oauth2/provider/OAuth2Authentication.java new file mode 100644 index 000000000..f38e90af1 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/OAuth2Authentication.java @@ -0,0 +1,123 @@ +package org.springframework.security.oauth2.provider; + +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.CredentialsContainer; + +/** + * An OAuth 2 authentication token can contain two authentications: one for the client and one for the user. Since some + * OAuth authorization grants don't require user authentication, the user authentication may be null. + * + *

+ * + * @author Ryan Heaton + */ +public class OAuth2Authentication extends AbstractAuthenticationToken { + + private static final long serialVersionUID = -4809832298438307309L; + + private final OAuth2Request storedRequest; + + private final Authentication userAuthentication; + + /** + * Construct an OAuth 2 authentication. Since some grant types don't require user authentication, the user + * authentication may be null. + * + * @param storedRequest The authorization request (must not be null). + * @param userAuthentication The user authentication (possibly null). + */ + public OAuth2Authentication(OAuth2Request storedRequest, Authentication userAuthentication) { + super(userAuthentication == null ? storedRequest.getAuthorities() : userAuthentication.getAuthorities()); + this.storedRequest = storedRequest; + this.userAuthentication = userAuthentication; + } + + public Object getCredentials() { + return ""; + } + + public Object getPrincipal() { + return this.userAuthentication == null ? this.storedRequest.getClientId() : this.userAuthentication + .getPrincipal(); + } + + /** + * Convenience method to check if there is a user associated with this token, or just a client application. + * + * @return true if this token represents a client app not acting on behalf of a user + */ + public boolean isClientOnly() { + return userAuthentication == null; + } + + /** + * The authorization request containing details of the client application. + * + * @return The client authentication. + */ + public OAuth2Request getOAuth2Request() { + return storedRequest; + } + + /** + * The user authentication. + * + * @return The user authentication. + */ + public Authentication getUserAuthentication() { + return userAuthentication; + } + + @Override + public boolean isAuthenticated() { + return this.storedRequest.isApproved() + && (this.userAuthentication == null || this.userAuthentication.isAuthenticated()); + } + + @Override + public void eraseCredentials() { + super.eraseCredentials(); + if (this.userAuthentication != null && CredentialsContainer.class.isAssignableFrom(this.userAuthentication.getClass())) { + CredentialsContainer.class.cast(this.userAuthentication).eraseCredentials(); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof OAuth2Authentication)) { + return false; + } + if (!super.equals(o)) { + return false; + } + + OAuth2Authentication that = (OAuth2Authentication) o; + + if (!storedRequest.equals(that.storedRequest)) { + return false; + } + if (userAuthentication != null ? !userAuthentication.equals(that.userAuthentication) + : that.userAuthentication != null) { + return false; + } + + if (getDetails()!=null ? !getDetails().equals(that.getDetails()) : that.getDetails()!=null) { + // return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + storedRequest.hashCode(); + result = 31 * result + (userAuthentication != null ? userAuthentication.hashCode() : 0); + return result; + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/OAuth2Request.java b/src/main/java/org/springframework/security/oauth2/provider/OAuth2Request.java new file mode 100644 index 000000000..c15ca520b --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/OAuth2Request.java @@ -0,0 +1,253 @@ +package org.springframework.security.oauth2.provider; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.oauth2.common.util.OAuth2Utils; + +/** + * Represents a stored authorization or token request. Used as part of the OAuth2Authentication object to store a + * request's authentication information. Does not expose public setters so that clients can not mutate state if they + * respect the declared type of the request. + * + *

+ * + * @author Amanda Anganes + * @author Dave Syer + * + */ +public class OAuth2Request extends BaseRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * Resolved resource IDs. This set may change during request processing. + */ + private Set resourceIds = new HashSet(); + + /** + * Resolved granted authorities for this request. May change during request processing. + */ + private Collection authorities = new HashSet(); + + /** + * Whether the request has been approved by the end user (or other process). This will be altered by the User + * Approval Endpoint and/or the UserApprovalHandler as appropriate. + */ + private boolean approved = false; + + /** + * Will be non-null if the request is for a token to be refreshed (the original grant type might still be available + * via {@link #getGrantType()}). + */ + private TokenRequest refresh = null; + + /** + * The resolved redirect URI of this request. A URI may be present in the original request, in the + * authorizationParameters, or it may not be provided, in which case it will be defaulted (by processing classes) to + * the Client's default registered value. + */ + private String redirectUri; + + /** + * Resolved requested response types initialized (by the OAuth2RequestFactory) with the response types originally + * requested. + */ + private Set responseTypes = new HashSet(); + + /** + * Extension point for custom processing classes which may wish to store additional information about the OAuth2 + * request. Since this class is serializable, all members of this map must also be serializable. + */ + private Map extensions = new HashMap(); + + public OAuth2Request(Map requestParameters, String clientId, + Collection authorities, boolean approved, Set scope, + Set resourceIds, String redirectUri, Set responseTypes, + Map extensionProperties) { + setClientId(clientId); + setRequestParameters(requestParameters); + setScope(scope); + if (resourceIds != null) { + this.resourceIds = new HashSet(resourceIds); + } + if (authorities != null) { + this.authorities = new HashSet(authorities); + } + this.approved = approved; + if (responseTypes != null) { + this.responseTypes = new HashSet(responseTypes); + } + this.redirectUri = redirectUri; + if (extensionProperties != null) { + this.extensions = extensionProperties; + } + } + + protected OAuth2Request(OAuth2Request other) { + this(other.getRequestParameters(), other.getClientId(), other.getAuthorities(), other.isApproved(), other + .getScope(), other.getResourceIds(), other.getRedirectUri(), other.getResponseTypes(), other + .getExtensions()); + } + + protected OAuth2Request(String clientId) { + setClientId(clientId); + } + + protected OAuth2Request() { + super(); + } + + public String getRedirectUri() { + return redirectUri; + } + + public Set getResponseTypes() { + return responseTypes; + } + + public Collection getAuthorities() { + return authorities; + } + + public boolean isApproved() { + return approved; + } + + public Set getResourceIds() { + return resourceIds; + } + + public Map getExtensions() { + return extensions; + } + + /** + * Update the request parameters and return a new object with the same properties except the parameters. + * @param parameters new parameters replacing the existing ones + * @return a new OAuth2Request + */ + public OAuth2Request createOAuth2Request(Map parameters) { + return new OAuth2Request(parameters, getClientId(), authorities, approved, getScope(), resourceIds, + redirectUri, responseTypes, extensions); + } + + /** + * Update the scope and create a new request. All the other properties are the same (including the request + * parameters). + * + * @param scope the new scope + * @return a new request with the narrowed scope + */ + public OAuth2Request narrowScope(Set scope) { + OAuth2Request request = new OAuth2Request(getRequestParameters(), getClientId(), authorities, approved, scope, + resourceIds, redirectUri, responseTypes, extensions); + request.refresh = this.refresh; + return request; + } + + public OAuth2Request refresh(TokenRequest tokenRequest) { + OAuth2Request request = new OAuth2Request(getRequestParameters(), getClientId(), authorities, approved, + getScope(), resourceIds, redirectUri, responseTypes, extensions); + request.refresh = tokenRequest; + return request; + } + + /** + * @return true if this request is known to be for a token to be refreshed + */ + public boolean isRefresh() { + return refresh != null; + } + + /** + * If this request was for an access token to be refreshed, then the {@link TokenRequest} that led to the refresh + * may be available here if it is known. + * + * @return the refresh token request (may be null) + */ + public TokenRequest getRefreshTokenRequest() { + return refresh; + } + + /** + * Tries to discover the grant type requested for the token associated with this request. + * + * @return the grant type if known, or null otherwise + */ + public String getGrantType() { + if (getRequestParameters().containsKey(OAuth2Utils.GRANT_TYPE)) { + return getRequestParameters().get(OAuth2Utils.GRANT_TYPE); + } + if (getRequestParameters().containsKey(OAuth2Utils.RESPONSE_TYPE)) { + String response = getRequestParameters().get(OAuth2Utils.RESPONSE_TYPE); + if (response.contains("token")) { + return "implicit"; + } + } + return null; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (approved ? 1231 : 1237); + result = prime * result + ((authorities == null) ? 0 : authorities.hashCode()); + result = prime * result + ((extensions == null) ? 0 : extensions.hashCode()); + result = prime * result + ((redirectUri == null) ? 0 : redirectUri.hashCode()); + result = prime * result + ((resourceIds == null) ? 0 : resourceIds.hashCode()); + result = prime * result + ((responseTypes == null) ? 0 : responseTypes.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + OAuth2Request other = (OAuth2Request) obj; + if (approved != other.approved) + return false; + if (authorities == null) { + if (other.authorities != null) + return false; + } + else if (!authorities.equals(other.authorities)) + return false; + if (extensions == null) { + if (other.extensions != null) + return false; + } + else if (!extensions.equals(other.extensions)) + return false; + if (redirectUri == null) { + if (other.redirectUri != null) + return false; + } + else if (!redirectUri.equals(other.redirectUri)) + return false; + if (resourceIds == null) { + if (other.resourceIds != null) + return false; + } + else if (!resourceIds.equals(other.resourceIds)) + return false; + if (responseTypes == null) { + if (other.responseTypes != null) + return false; + } + else if (!responseTypes.equals(other.responseTypes)) + return false; + return true; + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/OAuth2RequestFactory.java b/src/main/java/org/springframework/security/oauth2/provider/OAuth2RequestFactory.java new file mode 100644 index 000000000..058650848 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/OAuth2RequestFactory.java @@ -0,0 +1,83 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springframework.security.oauth2.provider; + +import java.util.Map; + +/** + * Strategy for managing OAuth2 requests: {@link AuthorizationRequest}, {@link TokenRequest}, {@link OAuth2Request}. + * + *

+ * + * @author Dave Syer + * @author Amanda Anganes + * + */ +public interface OAuth2RequestFactory { + + /** + * Create a new {@link AuthorizationRequest} extracting all the needed information from the incoming parameter map, + * and initializing all individual fields on the {@link AuthorizationRequest} to reasonable values. When a class + * uses the factory to create an {@link AuthorizationRequest}, it should not need to access the parameter map + * directly afterwards. + * + * Typical implementations would initialize the individual fields on the {@link AuthorizationRequest} with the + * values requested in the original parameter map. It may also load the client details from the client id provided + * and validate the grant type and scopes, populating any fields in the request that are known only to the + * authorization server. + * + * @param authorizationParameters the parameters in the request + * @return a new AuthorizationRequest + */ + AuthorizationRequest createAuthorizationRequest(Map authorizationParameters); + + /** + * Create a new {@link OAuth2Request} by extracting the needed information from the current + * {@link AuthorizationRequest} object. + * + * @param request the request to be converted + * @return an immutable object for storage + */ + OAuth2Request createOAuth2Request(AuthorizationRequest request); + + /** + * Create a new {@link OAuth2Request} by extracting the needed information from the current {@link TokenRequest} + * object. + * @param client TODO + * @param tokenRequest the request to be converted + * + * @return am immutable object for storage + */ + OAuth2Request createOAuth2Request(ClientDetails client, TokenRequest tokenRequest); + + /** + * Create a new {@link TokenRequest} by extracting the needed information from the incoming request parameter map. + * + * @param requestParameters the parameters in the request + * @param authenticatedClient the client that authenticated during the token request + * @return a new TokenRequest + */ + TokenRequest createTokenRequest(Map requestParameters, ClientDetails authenticatedClient); + + /** + * Create a new {@link TokenRequest} from an {@link AuthorizationRequest}. Principally used by the + * AuthorizationEndpoint during the implicit flow. + * + * @param authorizationRequest the incoming request + * @param grantType the grant type for the token request + * @return a new token request + */ + TokenRequest createTokenRequest(AuthorizationRequest authorizationRequest, String grantType); + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/provider/OAuth2RequestValidator.java b/src/main/java/org/springframework/security/oauth2/provider/OAuth2RequestValidator.java new file mode 100644 index 000000000..e373a7d91 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/OAuth2RequestValidator.java @@ -0,0 +1,33 @@ +package org.springframework.security.oauth2.provider; + +import org.springframework.security.oauth2.common.exceptions.InvalidScopeException; + +/** + * Validation interface for OAuth2 requests to the {@link AuthorizationEndpoint} and {@link TokenEndpoint}. + * + *

+ * + * @author Amanda Anganes + * + */ +public interface OAuth2RequestValidator { + + /** + * Ensure that the client has requested a valid set of scopes. + * + * @param authorizationRequest the AuthorizationRequest to be validated + * @param client the client that is making the request + * @throws InvalidScopeException if a requested scope is invalid + */ + public void validateScope(AuthorizationRequest authorizationRequest, ClientDetails client) throws InvalidScopeException; + + /** + * Ensure that the client has requested a valid set of scopes. + * + * @param tokenRequest the TokenRequest to be validated + * @param client the client that is making the request + * @throws InvalidScopeException if a requested scope is invalid + */ + public void validateScope(TokenRequest tokenRequest, ClientDetails client) throws InvalidScopeException; + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/SecurityContextAccessor.java b/src/main/java/org/springframework/security/oauth2/provider/SecurityContextAccessor.java new file mode 100644 index 000000000..4070ba9ed --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/SecurityContextAccessor.java @@ -0,0 +1,40 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springframework.security.oauth2.provider; + +import java.util.Set; + +import org.springframework.security.core.GrantedAuthority; + +/** + * Strategy for accessing useful information about the current security context. + * + *

+ * + * @author Dave Syer + * + */ +public interface SecurityContextAccessor { + + /** + * @return true if the current context represents a user + */ + boolean isUser(); + + /** + * Get the current granted authorities (never null) + */ + Set getAuthorities(); + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/TokenGranter.java b/src/main/java/org/springframework/security/oauth2/provider/TokenGranter.java new file mode 100644 index 000000000..c2846015e --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/TokenGranter.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.provider; + +import org.springframework.security.oauth2.common.OAuth2AccessToken; + +/** + * Interface for granters of access tokens. Various grant types are defined in the specification, and each of those has + * an implementation, leaving room for extensions to the specification as needed. + * + *

+ * + * @author Dave Syer + * + */ +public interface TokenGranter { + + OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest); + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/TokenRequest.java b/src/main/java/org/springframework/security/oauth2/provider/TokenRequest.java new file mode 100644 index 000000000..5f6a29992 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/TokenRequest.java @@ -0,0 +1,98 @@ +package org.springframework.security.oauth2.provider; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.security.oauth2.common.util.OAuth2Utils; + +/** + * Represents an OAuth2 token request, made at the {@link TokenEndpoint}. The requestParameters map should contain the + * original, unmodified parameters from the original OAuth2 request. + * + * In the implicit flow, a token is requested through the {@link AuthorizationEndpoint} directly, and in that case the + * {@link AuthorizationRequest} is converted into a {@link TokenRequest} for processing through the token granting + * chain. + * + *

+ * + * @author Amanda Anganes + * @author Dave Syer + * + */ +@SuppressWarnings("serial") +public class TokenRequest extends BaseRequest { + + private String grantType; + + /** + * Default constructor + */ + protected TokenRequest() { + } + + /** + * Full constructor. Sets this TokenRequest's requestParameters map to an unmodifiable version of the one provided. + * + * @param requestParameters + * @param clientId + * @param scope + * @param grantType + */ + public TokenRequest(Map requestParameters, String clientId, Collection scope, + String grantType) { + setClientId(clientId); + setRequestParameters(requestParameters); + setScope(scope); + this.grantType = grantType; + } + + public String getGrantType() { + return grantType; + } + + public void setGrantType(String grantType) { + this.grantType = grantType; + } + + public void setClientId(String clientId) { + super.setClientId(clientId); + } + + /** + * Set the scope value. If the collection contains only a single scope value, this method will parse that value into + * a collection using {@link OAuth2Utils#parseParameterList}. + * + * @see AuthorizationRequest#setScope + * + * @param scope + */ + public void setScope(Collection scope) { + super.setScope(scope); + } + + /** + * Set the Request Parameters on this authorization request, which represent the original request parameters and + * should never be changed during processing. The map passed in is wrapped in an unmodifiable map instance. + * + * @see AuthorizationRequest#setRequestParameters + * + * @param requestParameters + */ + public void setRequestParameters(Map requestParameters) { + super.setRequestParameters(requestParameters); + } + + public OAuth2Request createOAuth2Request(ClientDetails client) { + Map requestParameters = getRequestParameters(); + HashMap modifiable = new HashMap(requestParameters); + // Remove password if present to prevent leaks + modifiable.remove("password"); + modifiable.remove("client_secret"); + // Add grant type so it can be retrieved from OAuth2Request + modifiable.put(OAuth2Utils.GRANT_TYPE, grantType); + return new OAuth2Request(modifiable, client.getClientId(), client.getAuthorities(), true, this.getScope(), + client.getResourceIds(), null, null, null); + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/approval/Approval.java b/src/main/java/org/springframework/security/oauth2/provider/approval/Approval.java new file mode 100644 index 000000000..b2287429f --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/approval/Approval.java @@ -0,0 +1,170 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.provider.approval; + +import java.util.Calendar; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import org.springframework.security.oauth2.common.util.JsonDateDeserializer; +import org.springframework.security.oauth2.common.util.JsonDateSerializer; + +/** + *

+ * + * @author Dave Syer + * @author Vidya Val + * + */ +@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) +public class Approval { + + private String userId; + + private String clientId; + + private String scope; + + public enum ApprovalStatus { + APPROVED, + DENIED; + } + + private ApprovalStatus status; + + private Date expiresAt; + + private Date lastUpdatedAt; + + public Approval(String userId, String clientId, String scope, int expiresIn, ApprovalStatus status) { + this(userId, clientId, scope, new Date(), status, new Date()); + Calendar expiresAt = Calendar.getInstance(); + expiresAt.add(Calendar.MILLISECOND, expiresIn); + setExpiresAt(expiresAt.getTime()); + } + + public Approval(String userId, String clientId, String scope, Date expiresAt, ApprovalStatus status) { + this(userId, clientId, scope, expiresAt, status, new Date()); + } + + public Approval(String userId, String clientId, String scope, Date expiresAt, ApprovalStatus status, Date lastUpdatedAt) { + setUserId(userId); + setClientId(clientId); + setScope(scope); + setExpiresAt(expiresAt); + this.status = status; + this.lastUpdatedAt = lastUpdatedAt; + } + + protected Approval() { } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId == null ? "" : userId; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId == null ? "" : clientId; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope == null ? "" : scope; + } + + @JsonSerialize(using = JsonDateSerializer.class, include = JsonSerialize.Inclusion.NON_NULL) + public Date getExpiresAt() { + return expiresAt; + } + + @JsonDeserialize(using = JsonDateDeserializer.class) + public void setExpiresAt(Date expiresAt) { + if (expiresAt == null) { + Calendar thirtyMinFromNow = Calendar.getInstance(); + thirtyMinFromNow.add(Calendar.MINUTE, 30); + expiresAt = thirtyMinFromNow.getTime(); + } + this.expiresAt = expiresAt; + } + + @JsonSerialize(using = JsonDateSerializer.class, include = JsonSerialize.Inclusion.NON_NULL) + public Date getLastUpdatedAt() { + return lastUpdatedAt; + } + + @JsonDeserialize(using = JsonDateDeserializer.class) + public void setLastUpdatedAt(Date lastUpdatedAt) { + this.lastUpdatedAt = lastUpdatedAt; + } + + @JsonIgnore + public boolean isCurrentlyActive() { + return expiresAt != null && expiresAt.after(new Date()); + } + + @JsonIgnore + public boolean isApproved() { + return isCurrentlyActive() && status==ApprovalStatus.APPROVED; + } + + public void setStatus(ApprovalStatus status) { + this.status = status; + } + + public ApprovalStatus getStatus() { + return status; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + userId.hashCode(); + result = prime * result + clientId.hashCode(); + result = prime * result + scope.hashCode(); + result = prime * result + status.hashCode(); + return result; + } + + @Override + public boolean equals(Object o) { + if (o == null || !(o instanceof Approval)) { + return false; + } + Approval other = (Approval) o; + return userId.equals(other.userId) && clientId.equals(other.clientId) && scope.equals(other.scope) && status == other.status; + } + + @Override + public String toString() { + return String.format("[%s, %s, %s, %s, %s, %s]", userId, scope, clientId, expiresAt, status.toString(), lastUpdatedAt); + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/approval/ApprovalStore.java b/src/main/java/org/springframework/security/oauth2/provider/approval/ApprovalStore.java new file mode 100644 index 000000000..1889caf66 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/approval/ApprovalStore.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.oauth2.provider.approval; + +import java.util.Collection; + +/** + * Interface for saving, retrieving and revoking user approvals (per client, per scope). + * + *

+ * + * @author Dave Syer + * + */ +public interface ApprovalStore { + + public boolean addApprovals(Collection approvals); + + public boolean revokeApprovals(Collection approvals); + + public Collection getApprovals(String userId, String clientId); + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/approval/ApprovalStoreUserApprovalHandler.java b/src/main/java/org/springframework/security/oauth2/provider/approval/ApprovalStoreUserApprovalHandler.java new file mode 100644 index 000000000..74f4bbb72 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/approval/ApprovalStoreUserApprovalHandler.java @@ -0,0 +1,258 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.provider.approval; + +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.common.util.OAuth2Utils; +import org.springframework.security.oauth2.provider.AuthorizationRequest; +import org.springframework.security.oauth2.provider.ClientDetails; +import org.springframework.security.oauth2.provider.ClientDetailsService; +import org.springframework.security.oauth2.provider.ClientRegistrationException; +import org.springframework.security.oauth2.provider.OAuth2RequestFactory; +import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus; +import org.springframework.util.Assert; + +/** + * A user approval handler that remembers approval decisions by consulting existing approvals. + * + *

+ * + * @author Dave Syer + * + */ +public class ApprovalStoreUserApprovalHandler implements UserApprovalHandler, InitializingBean { + + private static Log logger = LogFactory.getLog(ApprovalStoreUserApprovalHandler.class); + + private String scopePrefix = OAuth2Utils.SCOPE_PREFIX; + + private ApprovalStore approvalStore; + + private int approvalExpirySeconds = -1; + + private ClientDetailsService clientDetailsService; + + /** + * Service to load client details (optional) for auto approval checks. + * + * @param clientDetailsService a client details service + */ + public void setClientDetailsService(ClientDetailsService clientDetailsService) { + this.clientDetailsService = clientDetailsService; + } + + /** + * The prefix applied to incoming parameters that signal approval or denial of a scope. + * + * @param scopePrefix the prefix (default {@link OAuth2Utils#SCOPE_PREFIX}) + */ + public void setScopePrefix(String scopePrefix) { + this.scopePrefix = scopePrefix; + } + + /** + * @param store the approval to set + */ + public void setApprovalStore(ApprovalStore store) { + this.approvalStore = store; + } + + private OAuth2RequestFactory requestFactory; + + public void setRequestFactory(OAuth2RequestFactory requestFactory) { + this.requestFactory = requestFactory; + } + + public void setApprovalExpiryInSeconds(int approvalExpirySeconds) { + this.approvalExpirySeconds = approvalExpirySeconds; + } + + public void afterPropertiesSet() { + Assert.state(approvalStore != null, "ApprovalStore must be provided"); + Assert.state(requestFactory != null, "OAuth2RequestFactory must be provided"); + } + + public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) { + return authorizationRequest.isApproved(); + } + + public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest, + Authentication userAuthentication) { + + String clientId = authorizationRequest.getClientId(); + Collection requestedScopes = authorizationRequest.getScope(); + Set approvedScopes = new HashSet(); + Set validUserApprovedScopes = new HashSet(); + + if (clientDetailsService != null) { + try { + ClientDetails client = clientDetailsService.loadClientByClientId(clientId); + for (String scope : requestedScopes) { + if (client.isAutoApprove(scope)) { + approvedScopes.add(scope); + } + } + if (approvedScopes.containsAll(requestedScopes)) { + // gh-877 - if all scopes are auto approved, approvals still need to be added to the approval store. + Set approvals = new HashSet(); + Date expiry = computeExpiry(); + for (String approvedScope : approvedScopes) { + approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(), + approvedScope, expiry, ApprovalStatus.APPROVED)); + } + approvalStore.addApprovals(approvals); + + authorizationRequest.setApproved(true); + return authorizationRequest; + } + } + catch (ClientRegistrationException e) { + logger.warn("Client registration problem prevent autoapproval check for client=" + clientId); + } + } + + if (logger.isDebugEnabled()) { + StringBuilder builder = new StringBuilder("Looking up user approved authorizations for "); + builder.append("client_id=" + clientId); + builder.append(" and username=" + userAuthentication.getName()); + logger.debug(builder.toString()); + } + + // Find the stored approvals for that user and client + Collection userApprovals = approvalStore.getApprovals(userAuthentication.getName(), clientId); + + // Look at the scopes and see if they have expired + Date today = new Date(); + for (Approval approval : userApprovals) { + if (approval.getExpiresAt().after(today)) { + if (approval.getStatus() == ApprovalStatus.APPROVED) { + validUserApprovedScopes.add(approval.getScope()); + approvedScopes.add(approval.getScope()); + } + } + } + + if (logger.isDebugEnabled()) { + logger.debug("Valid user approved/denied scopes are " + validUserApprovedScopes); + } + + // If the requested scopes have already been acted upon by the user, + // this request is approved + if (validUserApprovedScopes.containsAll(requestedScopes)) { + approvedScopes.retainAll(requestedScopes); + // Set only the scopes that have been approved by the user + authorizationRequest.setScope(approvedScopes); + authorizationRequest.setApproved(true); + } + + return authorizationRequest; + + } + + private Date computeExpiry() { + Calendar expiresAt = Calendar.getInstance(); + if (approvalExpirySeconds == -1) { // use default of 1 month + expiresAt.add(Calendar.MONTH, 1); + } + else { + expiresAt.add(Calendar.SECOND, approvalExpirySeconds); + } + return expiresAt.getTime(); + } + + /** + * Requires the authorization request to be explicitly approved, including all individual scopes, and the user to be + * authenticated. A scope that was requested in the authorization request can be approved by sending a request + * parameter scope.<scopename> equal to "true" or "approved" (otherwise it will be assumed to + * have been denied). The {@link ApprovalStore} will be updated to reflect the inputs. + * + * @param authorizationRequest The authorization request. + * @param userAuthentication the current user authentication + * + * @return An approved request if all scopes have been approved by the current user. + */ + public AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest, + Authentication userAuthentication) { + // Get the approved scopes + Set requestedScopes = authorizationRequest.getScope(); + Set approvedScopes = new HashSet(); + Set approvals = new HashSet(); + + Date expiry = computeExpiry(); + + // Store the scopes that have been approved / denied + Map approvalParameters = authorizationRequest.getApprovalParameters(); + for (String requestedScope : requestedScopes) { + String approvalParameter = scopePrefix + requestedScope; + String value = approvalParameters.get(approvalParameter); + value = value == null ? "" : value.toLowerCase(); + if ("true".equals(value) || value.startsWith("approve")) { + approvedScopes.add(requestedScope); + approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(), + requestedScope, expiry, ApprovalStatus.APPROVED)); + } + else { + approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(), + requestedScope, expiry, ApprovalStatus.DENIED)); + } + } + approvalStore.addApprovals(approvals); + + boolean approved; + authorizationRequest.setScope(approvedScopes); + if (approvedScopes.isEmpty() && !requestedScopes.isEmpty()) { + approved = false; + } + else { + approved = true; + } + authorizationRequest.setApproved(approved); + return authorizationRequest; + } + + @Override + public Map getUserApprovalRequest(AuthorizationRequest authorizationRequest, + Authentication userAuthentication) { + Map model = new HashMap(); + model.putAll(authorizationRequest.getRequestParameters()); + Map scopes = new LinkedHashMap(); + for (String scope : authorizationRequest.getScope()) { + scopes.put(scopePrefix + scope, "false"); + } + for (Approval approval : approvalStore.getApprovals(userAuthentication.getName(), + authorizationRequest.getClientId())) { + if (authorizationRequest.getScope().contains(approval.getScope())) { + scopes.put(scopePrefix + approval.getScope(), + approval.getStatus() == ApprovalStatus.APPROVED ? "true" : "false"); + } + } + model.put("scopes", scopes); + return model; + } +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/approval/JdbcApprovalStore.java b/src/main/java/org/springframework/security/oauth2/provider/approval/JdbcApprovalStore.java new file mode 100644 index 000000000..d88dfeb0d --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/approval/JdbcApprovalStore.java @@ -0,0 +1,231 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.oauth2.provider.approval; + +import static org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus.APPROVED; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.Collection; +import java.util.Date; +import java.util.List; + +import javax.sql.DataSource; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.PreparedStatementSetter; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus; +import org.springframework.util.Assert; + +/** + *

+ * + * @author Dave Syer + * + */ +public class JdbcApprovalStore implements ApprovalStore { + + private final JdbcTemplate jdbcTemplate; + + private final Log logger = LogFactory.getLog(getClass()); + + private final RowMapper rowMapper = new AuthorizationRowMapper(); + + private static final String TABLE_NAME = "oauth_approvals"; + + private static final String FIELDS = "expiresAt,status,lastModifiedAt,userId,clientId,scope"; + + private static final String WHERE_KEY = "where userId=? and clientId=?"; + + private static final String WHERE_KEY_AND_SCOPE = WHERE_KEY + " and scope=?"; + + private static final String DEFAULT_ADD_APPROVAL_STATEMENT = String.format("insert into %s ( %s ) values (?,?,?,?,?,?)", TABLE_NAME, + FIELDS); + + private static final String DEFAULT_REFRESH_APPROVAL_STATEMENT = String.format( + "update %s set expiresAt=?, status=?, lastModifiedAt=? " + WHERE_KEY_AND_SCOPE, TABLE_NAME); + + private static final String DEFAULT_GET_APPROVAL_SQL = String.format("select %s from %s " + WHERE_KEY, FIELDS, TABLE_NAME); + + private static final String DEFAULT_DELETE_APPROVAL_SQL = String.format("delete from %s " + WHERE_KEY_AND_SCOPE, + TABLE_NAME); + + private static final String DEFAULT_EXPIRE_APPROVAL_STATEMENT = String.format("update %s set expiresAt = ? " + WHERE_KEY_AND_SCOPE, + TABLE_NAME); + + private String addApprovalStatement = DEFAULT_ADD_APPROVAL_STATEMENT; + + private String refreshApprovalStatement = DEFAULT_REFRESH_APPROVAL_STATEMENT; + + private String findApprovalStatement = DEFAULT_GET_APPROVAL_SQL; + + private String deleteApprovalStatment = DEFAULT_DELETE_APPROVAL_SQL; + + private String expireApprovalStatement = DEFAULT_EXPIRE_APPROVAL_STATEMENT; + + private boolean handleRevocationsAsExpiry = false; + + public JdbcApprovalStore(DataSource dataSource) { + Assert.notNull(dataSource); + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + public void setHandleRevocationsAsExpiry(boolean handleRevocationsAsExpiry) { + this.handleRevocationsAsExpiry = handleRevocationsAsExpiry; + } + + public void setAddApprovalStatement(String addApprovalStatement) { + this.addApprovalStatement = addApprovalStatement; + } + + public void setFindApprovalStatement(String findApprovalStatement) { + this.findApprovalStatement = findApprovalStatement; + } + + public void setDeleteApprovalStatment(String deleteApprovalStatment) { + this.deleteApprovalStatment = deleteApprovalStatment; + } + + public void setExpireApprovalStatement(String expireApprovalStatement) { + this.expireApprovalStatement = expireApprovalStatement; + } + + public void setRefreshApprovalStatement(String refreshApprovalStatement) { + this.refreshApprovalStatement = refreshApprovalStatement; + } + + @Override + public boolean addApprovals(final Collection approvals) { + if (logger.isDebugEnabled()) { + logger.debug(String.format("adding approvals: [%s]", approvals)); + } + boolean success = true; + for (Approval approval : approvals) { + if (!updateApproval(refreshApprovalStatement, approval)) { + if (!updateApproval(addApprovalStatement, approval)) { + success = false; + } + } + } + return success; + } + + @Override + public boolean revokeApprovals(Collection approvals) { + if (logger.isDebugEnabled()) { + logger.debug(String.format("Revoking approvals: [%s]", approvals)); + } + boolean success = true; + for (final Approval approval : approvals) { + if (handleRevocationsAsExpiry) { + int refreshed = jdbcTemplate.update(expireApprovalStatement, new PreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps) throws SQLException { + ps.setTimestamp(1, new Timestamp(System.currentTimeMillis())); + ps.setString(2, approval.getUserId()); + ps.setString(3, approval.getClientId()); + ps.setString(4, approval.getScope()); + } + }); + if (refreshed != 1) { + success = false; + } + } + else { + int refreshed = jdbcTemplate.update(deleteApprovalStatment, new PreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps) throws SQLException { + ps.setString(1, approval.getUserId()); + ps.setString(2, approval.getClientId()); + ps.setString(3, approval.getScope()); + } + }); + if (refreshed != 1) { + success = false; + } + } + } + return success; + } + + public boolean purgeExpiredApprovals() { + logger.debug("Purging expired approvals from database"); + try { + int deleted = jdbcTemplate.update(deleteApprovalStatment + " where expiresAt <= ?", + new PreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps) throws SQLException { + ps.setTimestamp(1, new Timestamp(new Date().getTime())); + } + }); + if (logger.isDebugEnabled()) { + logger.debug(deleted + " expired approvals deleted"); + } + } + catch (DataAccessException ex) { + logger.error("Error purging expired approvals", ex); + return false; + } + return true; + } + + @Override + public List getApprovals(String userName, String clientId) { + return jdbcTemplate.query(findApprovalStatement, rowMapper, userName, clientId); + } + + private boolean updateApproval(final String sql, final Approval approval) { + if (logger.isDebugEnabled()) { + logger.debug(String.format("refreshing approval: [%s]", approval)); + } + int refreshed = jdbcTemplate.update(sql, new PreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps) throws SQLException { + ps.setTimestamp(1, new Timestamp(approval.getExpiresAt().getTime())); + ps.setString(2, (approval.getStatus() == null ? APPROVED : approval.getStatus()).toString()); + ps.setTimestamp(3, new Timestamp(approval.getLastUpdatedAt().getTime())); + ps.setString(4, approval.getUserId()); + ps.setString(5, approval.getClientId()); + ps.setString(6, approval.getScope()); + } + }); + if (refreshed != 1) { + return false; + } + return true; + } + + private static class AuthorizationRowMapper implements RowMapper { + + @Override + public Approval mapRow(ResultSet rs, int rowNum) throws SQLException { + String userName = rs.getString(4); + String clientId = rs.getString(5); + String scope = rs.getString(6); + Date expiresAt = rs.getTimestamp(1); + String status = rs.getString(2); + Date lastUpdatedAt = rs.getTimestamp(3); + + return new Approval(userName, clientId, scope, expiresAt, ApprovalStatus.valueOf(status), lastUpdatedAt); + } + } +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/approval/TokenStoreUserApprovalHandler.java b/src/main/java/org/springframework/security/oauth2/provider/approval/TokenStoreUserApprovalHandler.java new file mode 100644 index 000000000..e18a9496f --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/approval/TokenStoreUserApprovalHandler.java @@ -0,0 +1,181 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.provider.approval; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.common.util.OAuth2Utils; +import org.springframework.security.oauth2.provider.AuthorizationRequest; +import org.springframework.security.oauth2.provider.ClientDetails; +import org.springframework.security.oauth2.provider.ClientDetailsService; +import org.springframework.security.oauth2.provider.ClientRegistrationException; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.OAuth2Request; +import org.springframework.security.oauth2.provider.OAuth2RequestFactory; +import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.util.Assert; + +/** + * A user approval handler that remembers approval decisions by consulting existing tokens. + * + *

+ * + * @author Dave Syer + * + */ +public class TokenStoreUserApprovalHandler implements UserApprovalHandler, InitializingBean { + + private static Log logger = LogFactory.getLog(TokenStoreUserApprovalHandler.class); + + private String approvalParameter = OAuth2Utils.USER_OAUTH_APPROVAL; + + private TokenStore tokenStore; + + private ClientDetailsService clientDetailsService; + + /** + * Service to load client details (optional) for auto approval checks. + * + * @param clientDetailsService a client details service + */ + public void setClientDetailsService(ClientDetailsService clientDetailsService) { + this.clientDetailsService = clientDetailsService; + } + + /** + * @param approvalParameter the approvalParameter to set + */ + public void setApprovalParameter(String approvalParameter) { + this.approvalParameter = approvalParameter; + } + + /** + * @param tokenStore the token store to set + */ + public void setTokenStore(TokenStore tokenStore) { + this.tokenStore = tokenStore; + } + + private OAuth2RequestFactory requestFactory; + + public void setRequestFactory(OAuth2RequestFactory requestFactory) { + this.requestFactory = requestFactory; + } + + @Override + public void afterPropertiesSet() { + Assert.state(tokenStore != null, "TokenStore must be provided"); + Assert.state(requestFactory != null, "OAuth2RequestFactory must be provided"); + } + + /** + * Basic implementation just requires the authorization request to be explicitly approved and the user to be + * authenticated. + * + * @param authorizationRequest The authorization request. + * @param userAuthentication the current user authentication + * + * @return Whether the specified request has been approved by the current user. + */ + @Override + public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) { + return authorizationRequest.isApproved(); + } + + @Override + public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest, Authentication userAuthentication) { + + boolean approved = false; + + String clientId = authorizationRequest.getClientId(); + Set scopes = authorizationRequest.getScope(); + if (clientDetailsService!=null) { + try { + ClientDetails client = clientDetailsService.loadClientByClientId(clientId); + approved = true; + for (String scope : scopes) { + if (!client.isAutoApprove(scope)) { + approved = false; + } + } + if (approved) { + authorizationRequest.setApproved(true); + return authorizationRequest; + } + } + catch (ClientRegistrationException e) { + logger.warn("Client registration problem prevent autoapproval check for client=" + clientId); + } + } + + OAuth2Request storedOAuth2Request = requestFactory.createOAuth2Request(authorizationRequest); + + OAuth2Authentication authentication = new OAuth2Authentication(storedOAuth2Request, userAuthentication); + if (logger.isDebugEnabled()) { + StringBuilder builder = new StringBuilder("Looking up existing token for "); + builder.append("client_id=" + clientId); + builder.append(", scope=" + scopes); + builder.append(" and username=" + userAuthentication.getName()); + logger.debug(builder.toString()); + } + + OAuth2AccessToken accessToken = tokenStore.getAccessToken(authentication); + if (logger.isDebugEnabled()) { + logger.debug("Existing access token=" + accessToken); + } + if (accessToken != null && !accessToken.isExpired()) { + if (logger.isDebugEnabled()) { + logger.debug("User already approved with token=" + accessToken); + } + // A token was already granted and is still valid, so this is already approved + approved = true; + } + else { + logger.debug("Checking explicit approval"); + approved = userAuthentication.isAuthenticated() && approved; + } + + authorizationRequest.setApproved(approved); + + return authorizationRequest; + } + + @Override + public AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest, Authentication userAuthentication) { + Map approvalParameters = authorizationRequest.getApprovalParameters(); + String flag = approvalParameters.get(approvalParameter); + boolean approved = flag != null && flag.toLowerCase().equals("true"); + authorizationRequest.setApproved(approved); + return authorizationRequest; + } + + @Override + public Map getUserApprovalRequest(AuthorizationRequest authorizationRequest, + Authentication userAuthentication) { + Map model = new HashMap(); + // In case of a redirect we might want the request parameters to be included + model.putAll(authorizationRequest.getRequestParameters()); + return model; + } +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/approval/UserApprovalHandler.java b/src/main/java/org/springframework/security/oauth2/provider/approval/UserApprovalHandler.java new file mode 100644 index 000000000..f5c087ab5 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/approval/UserApprovalHandler.java @@ -0,0 +1,79 @@ +package org.springframework.security.oauth2.provider.approval; + +import java.util.Map; + +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.provider.AuthorizationRequest; + +/** + * Basic interface for determining whether a given client authentication request has been + * approved by the current user. + * + *

+ * + * @author Ryan Heaton + * @author Dave Syer + * @author Amanda Anganes + */ +public interface UserApprovalHandler { + + /** + *

+ * Tests whether the specified authorization request has been approved by the current + * user (if there is one). + *

+ * + * @param authorizationRequest the authorization request. + * @param userAuthentication the user authentication for the current user. + * @return true if the request has been approved, false otherwise + */ + boolean isApproved(AuthorizationRequest authorizationRequest, + Authentication userAuthentication); + + /** + *

+ * Provides a hook for allowing requests to be pre-approved (skipping the User + * Approval Page). Some implementations may allow users to store approval decisions so + * that they only have to approve a site once. This method is called in the + * AuthorizationEndpoint before sending the user to the Approval page. If this method + * sets oAuth2Request.approved to true, the Approval page will be skipped. + *

+ * + * @param authorizationRequest the authorization request. + * @param userAuthentication the user authentication + * @return the AuthorizationRequest, modified if necessary + */ + AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest, + Authentication userAuthentication); + + /** + *

+ * Provides an opportunity to update the authorization request after the + * {@link AuthorizationRequest#setApprovalParameters(Map) approval parameters} are set + * but before it is checked for approval. Useful in cases where the incoming approval + * parameters contain richer information than just true/false (e.g. some scopes are + * approved, and others are rejected), implementations may need to be able to modify + * the {@link AuthorizationRequest} before a token is generated from it. + *

+ * + * @param authorizationRequest the authorization request. + * @param userAuthentication the user authentication + * @return the AuthorizationRequest, modified if necessary + */ + AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest, + Authentication userAuthentication); + + /** + * Generate a request for the authorization server to ask for the user's approval. + * Typically this will be rendered into a view (HTML etc.) to prompt for the approval, + * so it needs to contain information about the grant (scopes and client id for + * instance). + * + * @param authorizationRequest the authorization request + * @param userAuthentication the user authentication + * @return a model map for rendering to the user to ask for approval + */ + Map getUserApprovalRequest(AuthorizationRequest authorizationRequest, + Authentication userAuthentication); + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/code/AuthorizationCodeServices.java b/src/main/java/org/springframework/security/oauth2/provider/code/AuthorizationCodeServices.java new file mode 100644 index 000000000..16d7849b2 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/code/AuthorizationCodeServices.java @@ -0,0 +1,33 @@ +package org.springframework.security.oauth2.provider.code; + +import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; +import org.springframework.security.oauth2.provider.OAuth2Authentication; + +/** + * Services for issuing and storing authorization codes. + * + *

+ * + * @author Ryan Heaton + */ +public interface AuthorizationCodeServices { + + /** + * Create a authorization code for the specified authentications. + * + * @param authentication The authentications to store. + * @return The generated code. + */ + String createAuthorizationCode(OAuth2Authentication authentication); + + /** + * Consume a authorization code. + * + * @param code The authorization code to consume. + * @return The authentications associated with the code. + * @throws InvalidGrantException If the authorization code is invalid or expired. + */ + OAuth2Authentication consumeAuthorizationCode(String code) + throws InvalidGrantException; + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/code/JdbcAuthorizationCodeServices.java b/src/main/java/org/springframework/security/oauth2/provider/code/JdbcAuthorizationCodeServices.java new file mode 100644 index 000000000..47bf4060d --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/code/JdbcAuthorizationCodeServices.java @@ -0,0 +1,82 @@ +package org.springframework.security.oauth2.provider.code; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; + +import javax.sql.DataSource; + +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.support.SqlLobValue; +import org.springframework.security.oauth2.common.util.SerializationUtils; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.util.Assert; + +/** + * Implementation of authorization code services that stores the codes and authentication in a database. + * + *

+ * + * @author Ken Dombeck + * @author Dave Syer + */ +public class JdbcAuthorizationCodeServices extends RandomValueAuthorizationCodeServices { + + private static final String DEFAULT_SELECT_STATEMENT = "select code, authentication from oauth_code where code = ?"; + private static final String DEFAULT_INSERT_STATEMENT = "insert into oauth_code (code, authentication) values (?, ?)"; + private static final String DEFAULT_DELETE_STATEMENT = "delete from oauth_code where code = ?"; + + private String selectAuthenticationSql = DEFAULT_SELECT_STATEMENT; + private String insertAuthenticationSql = DEFAULT_INSERT_STATEMENT; + private String deleteAuthenticationSql = DEFAULT_DELETE_STATEMENT; + + private final JdbcTemplate jdbcTemplate; + + public JdbcAuthorizationCodeServices(DataSource dataSource) { + Assert.notNull(dataSource, "DataSource required"); + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Override + protected void store(String code, OAuth2Authentication authentication) { + jdbcTemplate.update(insertAuthenticationSql, + new Object[] { code, new SqlLobValue(SerializationUtils.serialize(authentication)) }, new int[] { + Types.VARCHAR, Types.BLOB }); + } + + public OAuth2Authentication remove(String code) { + OAuth2Authentication authentication; + + try { + authentication = jdbcTemplate.queryForObject(selectAuthenticationSql, + new RowMapper() { + public OAuth2Authentication mapRow(ResultSet rs, int rowNum) + throws SQLException { + return SerializationUtils.deserialize(rs.getBytes("authentication")); + } + }, code); + } catch (EmptyResultDataAccessException e) { + return null; + } + + if (authentication != null) { + jdbcTemplate.update(deleteAuthenticationSql, code); + } + + return authentication; + } + + public void setSelectAuthenticationSql(String selectAuthenticationSql) { + this.selectAuthenticationSql = selectAuthenticationSql; + } + + public void setInsertAuthenticationSql(String insertAuthenticationSql) { + this.insertAuthenticationSql = insertAuthenticationSql; + } + + public void setDeleteAuthenticationSql(String deleteAuthenticationSql) { + this.deleteAuthenticationSql = deleteAuthenticationSql; + } +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/code/RandomValueAuthorizationCodeServices.java b/src/main/java/org/springframework/security/oauth2/provider/code/RandomValueAuthorizationCodeServices.java new file mode 100644 index 000000000..48c51d4fa --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/code/RandomValueAuthorizationCodeServices.java @@ -0,0 +1,38 @@ +package org.springframework.security.oauth2.provider.code; + +import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; +import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; +import org.springframework.security.oauth2.provider.OAuth2Authentication; + +/** + * Base implementation for authorization code services that generates a random-value authorization code. + * + *

+ * + * @author Ryan Heaton + * @author Dave Syer + */ +public abstract class RandomValueAuthorizationCodeServices implements AuthorizationCodeServices { + + private RandomValueStringGenerator generator = new RandomValueStringGenerator(); + + protected abstract void store(String code, OAuth2Authentication authentication); + + protected abstract OAuth2Authentication remove(String code); + + public String createAuthorizationCode(OAuth2Authentication authentication) { + String code = generator.generate(); + store(code, authentication); + return code; + } + + public OAuth2Authentication consumeAuthorizationCode(String code) + throws InvalidGrantException { + OAuth2Authentication auth = this.remove(code); + if (auth == null) { + throw new InvalidGrantException("Invalid authorization code: " + code); + } + return auth; + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/endpoint/DefaultRedirectResolver.java b/src/main/java/org/springframework/security/oauth2/provider/endpoint/DefaultRedirectResolver.java new file mode 100644 index 000000000..444fd21ca --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/endpoint/DefaultRedirectResolver.java @@ -0,0 +1,234 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.oauth2.provider.endpoint; + +import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; +import org.springframework.security.oauth2.common.exceptions.InvalidRequestException; +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; +import org.springframework.security.oauth2.common.exceptions.RedirectMismatchException; +import org.springframework.security.oauth2.provider.ClientDetails; +import org.springframework.util.Assert; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * Default implementation for a redirect resolver. + * + *

+ * + * @author Ryan Heaton + * @author Dave Syer + */ +public class DefaultRedirectResolver implements RedirectResolver { + + private Collection redirectGrantTypes = Arrays.asList("implicit", "authorization_code"); + + private boolean matchSubdomains = false; + + private boolean matchPorts = true; + + /** + * Flag to indicate that requested URIs will match if they are a subdomain of the registered value. + * + * @param matchSubdomains the flag value to set (default true) + */ + public void setMatchSubdomains(boolean matchSubdomains) { + this.matchSubdomains = matchSubdomains; + } + + /** + * Flag that enables/disables port matching between the requested redirect URI and the registered redirect URI(s). + * + * @param matchPorts true to enable port matching, false to disable (defaults to true) + */ + public void setMatchPorts(boolean matchPorts) { + this.matchPorts = matchPorts; + } + + /** + * Grant types that are permitted to have a redirect uri. + * + * @param redirectGrantTypes the redirect grant types to set + */ + public void setRedirectGrantTypes(Collection redirectGrantTypes) { + this.redirectGrantTypes = new HashSet(redirectGrantTypes); + } + + public String resolveRedirect(String requestedRedirect, ClientDetails client) throws OAuth2Exception { + + Set authorizedGrantTypes = client.getAuthorizedGrantTypes(); + if (authorizedGrantTypes.isEmpty()) { + throw new InvalidGrantException("A client must have at least one authorized grant type."); + } + if (!containsRedirectGrantType(authorizedGrantTypes)) { + throw new InvalidGrantException( + "A redirect_uri can only be used by implicit or authorization_code grant types."); + } + + Set registeredRedirectUris = client.getRegisteredRedirectUri(); + if (registeredRedirectUris == null || registeredRedirectUris.isEmpty()) { + throw new InvalidRequestException("At least one redirect_uri must be registered with the client."); + } + return obtainMatchingRedirect(registeredRedirectUris, requestedRedirect); + } + + /** + * @param grantTypes some grant types + * @return true if the supplied grant types includes one or more of the redirect types + */ + private boolean containsRedirectGrantType(Set grantTypes) { + for (String type : grantTypes) { + if (redirectGrantTypes.contains(type)) { + return true; + } + } + return false; + } + + /** + * Whether the requested redirect URI "matches" the specified redirect URI. For a URL, this implementation tests if + * the user requested redirect starts with the registered redirect, so it would have the same host and root path if + * it is an HTTP URL. The port, userinfo, query params also matched. Request redirect uri path can include + * additional parameters which are ignored for the match + *

+ * For other (non-URL) cases, such as for some implicit clients, the redirect_uri must be an exact match. + * + * @param requestedRedirect The requested redirect URI. + * @param redirectUri The registered redirect URI. + * @return Whether the requested redirect URI "matches" the specified redirect URI. + */ + protected boolean redirectMatches(String requestedRedirect, String redirectUri) { + UriComponents requestedRedirectUri = UriComponentsBuilder.fromUriString(requestedRedirect).build(); + UriComponents registeredRedirectUri = UriComponentsBuilder.fromUriString(redirectUri).build(); + + boolean schemeMatch = isEqual(registeredRedirectUri.getScheme(), requestedRedirectUri.getScheme()); + boolean userInfoMatch = isEqual(registeredRedirectUri.getUserInfo(), requestedRedirectUri.getUserInfo()); + boolean hostMatch = hostMatches(registeredRedirectUri.getHost(), requestedRedirectUri.getHost()); + boolean portMatch = matchPorts ? registeredRedirectUri.getPort() == requestedRedirectUri.getPort() : true; + boolean pathMatch = isEqual(registeredRedirectUri.getPath(), + StringUtils.cleanPath(requestedRedirectUri.getPath())); + boolean queryParamMatch = matchQueryParams(registeredRedirectUri.getQueryParams(), + requestedRedirectUri.getQueryParams()); + + return schemeMatch && userInfoMatch && hostMatch && portMatch && pathMatch && queryParamMatch; + } + + + /** + * Checks whether the registered redirect uri query params key and values contains match the requested set + * + * The requested redirect uri query params are allowed to contain additional params which will be retained + * + * @param registeredRedirectUriQueryParams + * @param requestedRedirectUriQueryParams + * @return whether the params match + */ + private boolean matchQueryParams(MultiValueMap registeredRedirectUriQueryParams, + MultiValueMap requestedRedirectUriQueryParams) { + + + Iterator iter = registeredRedirectUriQueryParams.keySet().iterator(); + while (iter.hasNext()) { + String key = iter.next(); + List registeredRedirectUriQueryParamsValues = registeredRedirectUriQueryParams.get(key); + List requestedRedirectUriQueryParamsValues = requestedRedirectUriQueryParams.get(key); + + if (!registeredRedirectUriQueryParamsValues.equals(requestedRedirectUriQueryParamsValues)) { + return false; + } + } + + return true; + } + + + + /** + * Compares two strings but treats empty string or null equal + * + * @param str1 + * @param str2 + * @return true if strings are equal, false otherwise + */ + private boolean isEqual(String str1, String str2) { + if (StringUtils.isEmpty(str1)) { + return StringUtils.isEmpty(str2); + } else { + return str1.equals(str2); + } + } + + /** + * Check if host matches the registered value. + * + * @param registered the registered host. Can be null. + * @param requested the requested host. Can be null. + * @return true if they match + */ + protected boolean hostMatches(String registered, String requested) { + if (matchSubdomains) { + return isEqual(registered, requested) || (requested != null && requested.endsWith("." + registered)); + } + return isEqual(registered, requested); + } + + /** + * Attempt to match one of the registered URIs to the that of the requested one. + * + * @param redirectUris the set of the registered URIs to try and find a match. This cannot be null or empty. + * @param requestedRedirect the URI used as part of the request + * @return redirect uri + * @throws RedirectMismatchException if no match was found + */ + private String obtainMatchingRedirect(Set redirectUris, String requestedRedirect) { + Assert.notEmpty(redirectUris, "Redirect URIs cannot be empty"); + + if (redirectUris.size() == 1 && requestedRedirect == null) { + return redirectUris.iterator().next(); + } + + for (String redirectUri : redirectUris) { + if (requestedRedirect != null && redirectMatches(requestedRedirect, redirectUri)) { + // Initialize with the registered redirect-uri + UriComponentsBuilder redirectUriBuilder = UriComponentsBuilder.fromUriString(redirectUri); + + UriComponents requestedRedirectUri = UriComponentsBuilder.fromUriString(requestedRedirect).build(); + + if (this.matchSubdomains) { + redirectUriBuilder.host(requestedRedirectUri.getHost()); + } + if (!this.matchPorts) { + redirectUriBuilder.port(requestedRedirectUri.getPort()); + } + redirectUriBuilder.replaceQuery(requestedRedirectUri.getQuery()); // retain additional params (if any) + redirectUriBuilder.fragment(null); + return redirectUriBuilder.build().toUriString(); + } + } + + throw new RedirectMismatchException("Invalid redirect: " + requestedRedirect + + " does not match one of the registered values."); + } +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/endpoint/RedirectResolver.java b/src/main/java/org/springframework/security/oauth2/provider/endpoint/RedirectResolver.java new file mode 100644 index 000000000..3560c14e7 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/endpoint/RedirectResolver.java @@ -0,0 +1,25 @@ +package org.springframework.security.oauth2.provider.endpoint; + +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; +import org.springframework.security.oauth2.provider.ClientDetails; + +/** + * Basic interface for determining the redirect URI for a user agent. + * + *

+ * + * @author Ryan Heaton + */ +public interface RedirectResolver { + + /** + * Resolve the redirect for the specified client. + * + * @param requestedRedirect The redirect that was requested (may not be null). + * @param client The client for which we're resolving the redirect. + * @return The resolved redirect URI. + * @throws OAuth2Exception If the requested redirect is invalid for the specified client. + */ + String resolveRedirect(String requestedRedirect, ClientDetails client) throws OAuth2Exception; + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/error/AbstractOAuth2SecurityExceptionHandler.java b/src/main/java/org/springframework/security/oauth2/provider/error/AbstractOAuth2SecurityExceptionHandler.java new file mode 100644 index 000000000..6d5a3fb82 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/error/AbstractOAuth2SecurityExceptionHandler.java @@ -0,0 +1,100 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.provider.error; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; + +/** + * Convenient base class containing utility methods and dependency setters for security error handling concerns specific + * to OAuth2 resources. + * + *

+ * + * @author Dave Syer + * + */ +public abstract class AbstractOAuth2SecurityExceptionHandler { + + /** Logger available to subclasses */ + protected final Log logger = LogFactory.getLog(getClass()); + + private WebResponseExceptionTranslator exceptionTranslator = new DefaultWebResponseExceptionTranslator(); + + private OAuth2ExceptionRenderer exceptionRenderer = new DefaultOAuth2ExceptionRenderer(); + + // This is from Spring MVC. + private HandlerExceptionResolver handlerExceptionResolver = new DefaultHandlerExceptionResolver(); + + public void setExceptionTranslator(WebResponseExceptionTranslator exceptionTranslator) { + this.exceptionTranslator = exceptionTranslator; + } + + public void setExceptionRenderer(OAuth2ExceptionRenderer exceptionRenderer) { + this.exceptionRenderer = exceptionRenderer; + } + + protected final void doHandle(HttpServletRequest request, HttpServletResponse response, Exception authException) + throws IOException, ServletException { + try { + ResponseEntity result = exceptionTranslator.translate(authException); + result = enhanceResponse(result, authException); + exceptionRenderer.handleHttpEntityResponse(result, new ServletWebRequest(request, response)); + response.flushBuffer(); + } + catch (ServletException e) { + // Re-use some of the default Spring dispatcher behaviour - the exception came from the filter chain and + // not from an MVC handler so it won't be caught by the dispatcher (even if there is one) + if (handlerExceptionResolver.resolveException(request, response, this, e) == null) { + throw e; + } + } + catch (IOException e) { + throw e; + } + catch (RuntimeException e) { + throw e; + } + catch (Exception e) { + // Wrap other Exceptions. These are not expected to happen + throw new RuntimeException(e); + } + } + + /** + * Allow subclasses to manipulate the response before it is rendered. + * + * Note : Only the {@link ResponseEntity} should be enhanced. If the + * response body is to be customized, it should be done at the + * {@link WebResponseExceptionTranslator} level. + * + * @param result the response that was generated by the + * {@link #setExceptionTranslator(WebResponseExceptionTranslator) exception translator}. + * @param authException the authentication exception that is being handled + */ + protected ResponseEntity enhanceResponse(ResponseEntity result, + Exception authException) { + return result; + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/error/DefaultOAuth2ExceptionRenderer.java b/src/main/java/org/springframework/security/oauth2/provider/error/DefaultOAuth2ExceptionRenderer.java new file mode 100644 index 000000000..54f5baf4a --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/error/DefaultOAuth2ExceptionRenderer.java @@ -0,0 +1,131 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.provider.error; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpInputMessage; +import org.springframework.http.HttpOutputMessage; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.http.server.ServletServerHttpRequest; +import org.springframework.http.server.ServletServerHttpResponse; +import org.springframework.web.HttpMediaTypeNotAcceptableException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.context.request.ServletWebRequest; + +/** + * Default implementation of {@link OAuth2ExceptionRenderer} that can render the exceptions using message converters + * (just like regular Spring MVC endpoints). If the caller sends an appropriate Accept header he should get the right + * result as long as an appropriate message converter is provided. + * + *

+ * + * @author Dave Syer + * + */ +public class DefaultOAuth2ExceptionRenderer implements OAuth2ExceptionRenderer { + + private final Log logger = LogFactory.getLog(DefaultOAuth2ExceptionRenderer.class); + + private List> messageConverters = geDefaultMessageConverters(); + + public void setMessageConverters(List> messageConverters) { + this.messageConverters = messageConverters; + } + + public void handleHttpEntityResponse(HttpEntity responseEntity, ServletWebRequest webRequest) throws Exception { + if (responseEntity == null) { + return; + } + HttpInputMessage inputMessage = createHttpInputMessage(webRequest); + HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest); + if (responseEntity instanceof ResponseEntity && outputMessage instanceof ServerHttpResponse) { + ((ServerHttpResponse) outputMessage).setStatusCode(((ResponseEntity) responseEntity).getStatusCode()); + } + HttpHeaders entityHeaders = responseEntity.getHeaders(); + if (!entityHeaders.isEmpty()) { + outputMessage.getHeaders().putAll(entityHeaders); + } + Object body = responseEntity.getBody(); + if (body != null) { + writeWithMessageConverters(body, inputMessage, outputMessage); + } + else { + // flush headers + outputMessage.getBody(); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void writeWithMessageConverters(Object returnValue, HttpInputMessage inputMessage, + HttpOutputMessage outputMessage) throws IOException, HttpMediaTypeNotAcceptableException { + List acceptedMediaTypes = inputMessage.getHeaders().getAccept(); + if (acceptedMediaTypes.isEmpty()) { + acceptedMediaTypes = Collections.singletonList(MediaType.ALL); + } + MediaType.sortByQualityValue(acceptedMediaTypes); + Class returnValueType = returnValue.getClass(); + List allSupportedMediaTypes = new ArrayList(); + for (MediaType acceptedMediaType : acceptedMediaTypes) { + for (HttpMessageConverter messageConverter : messageConverters) { + if (messageConverter.canWrite(returnValueType, acceptedMediaType)) { + messageConverter.write(returnValue, acceptedMediaType, outputMessage); + if (logger.isDebugEnabled()) { + MediaType contentType = outputMessage.getHeaders().getContentType(); + if (contentType == null) { + contentType = acceptedMediaType; + } + logger.debug("Written [" + returnValue + "] as \"" + contentType + "\" using [" + + messageConverter + "]"); + } + return; + } + } + } + for (HttpMessageConverter messageConverter : messageConverters) { + allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); + } + throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes); + } + + private List> geDefaultMessageConverters() { + List> result = new ArrayList>(); + result.addAll(new RestTemplate().getMessageConverters()); + return result; + } + + private HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { + HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); + return new ServletServerHttpRequest(servletRequest); + } + + private HttpOutputMessage createHttpOutputMessage(NativeWebRequest webRequest) throws Exception { + HttpServletResponse servletResponse = (HttpServletResponse) webRequest.getNativeResponse(); + return new ServletServerHttpResponse(servletResponse); + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/error/DefaultWebResponseExceptionTranslator.java b/src/main/java/org/springframework/security/oauth2/provider/error/DefaultWebResponseExceptionTranslator.java new file mode 100644 index 000000000..c2c29b636 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/error/DefaultWebResponseExceptionTranslator.java @@ -0,0 +1,174 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.oauth2.provider.error; + +import java.io.IOException; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.oauth2.common.DefaultThrowableAnalyzer; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException; +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; +import org.springframework.security.web.util.ThrowableAnalyzer; +import org.springframework.web.HttpRequestMethodNotSupportedException; + +/** + * Default translator that converts exceptions into {@link OAuth2Exception}s. The output matches the OAuth 2.0 + * specification in terms of error response format and HTTP status code. + * + *

+ * + * @author Dave Syer + * + */ +public class DefaultWebResponseExceptionTranslator implements WebResponseExceptionTranslator { + + private ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer(); + + @Override + public ResponseEntity translate(Exception e) throws Exception { + + // Try to extract a SpringSecurityException from the stacktrace + Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e); + Exception ase = (OAuth2Exception) throwableAnalyzer.getFirstThrowableOfType(OAuth2Exception.class, causeChain); + + if (ase != null) { + return handleOAuth2Exception((OAuth2Exception) ase); + } + + ase = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, + causeChain); + if (ase != null) { + return handleOAuth2Exception(new UnauthorizedException(e.getMessage(), e)); + } + + ase = (AccessDeniedException) throwableAnalyzer + .getFirstThrowableOfType(AccessDeniedException.class, causeChain); + if (ase instanceof AccessDeniedException) { + return handleOAuth2Exception(new ForbiddenException(ase.getMessage(), ase)); + } + + ase = (HttpRequestMethodNotSupportedException) throwableAnalyzer.getFirstThrowableOfType( + HttpRequestMethodNotSupportedException.class, causeChain); + if (ase instanceof HttpRequestMethodNotSupportedException) { + return handleOAuth2Exception(new MethodNotAllowed(ase.getMessage(), ase)); + } + + return handleOAuth2Exception(new ServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), e)); + + } + + private ResponseEntity handleOAuth2Exception(OAuth2Exception e) throws IOException { + + int status = e.getHttpErrorCode(); + HttpHeaders headers = new HttpHeaders(); + headers.set("Cache-Control", "no-store"); + headers.set("Pragma", "no-cache"); + if (status == HttpStatus.UNAUTHORIZED.value() || (e instanceof InsufficientScopeException)) { + headers.set("WWW-Authenticate", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, e.getSummary())); + } + + ResponseEntity response = new ResponseEntity(e, headers, + HttpStatus.valueOf(status)); + + return response; + + } + + public void setThrowableAnalyzer(ThrowableAnalyzer throwableAnalyzer) { + this.throwableAnalyzer = throwableAnalyzer; + } + + @SuppressWarnings("serial") + private static class ForbiddenException extends OAuth2Exception { + + public ForbiddenException(String msg, Throwable t) { + super(msg, t); + } + + @Override + public String getOAuth2ErrorCode() { + return "access_denied"; + } + + @Override + public int getHttpErrorCode() { + return 403; + } + + } + + @SuppressWarnings("serial") + private static class ServerErrorException extends OAuth2Exception { + + public ServerErrorException(String msg, Throwable t) { + super(msg, t); + } + + @Override + public String getOAuth2ErrorCode() { + return "server_error"; + } + + @Override + public int getHttpErrorCode() { + return 500; + } + + } + + @SuppressWarnings("serial") + private static class UnauthorizedException extends OAuth2Exception { + + public UnauthorizedException(String msg, Throwable t) { + super(msg, t); + } + + @Override + public String getOAuth2ErrorCode() { + return "unauthorized"; + } + + @Override + public int getHttpErrorCode() { + return 401; + } + + } + + @SuppressWarnings("serial") + private static class MethodNotAllowed extends OAuth2Exception { + + public MethodNotAllowed(String msg, Throwable t) { + super(msg, t); + } + + @Override + public String getOAuth2ErrorCode() { + return "method_not_allowed"; + } + + @Override + public int getHttpErrorCode() { + return 405; + } + + } +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/error/OAuth2AuthenticationEntryPoint.java b/src/main/java/org/springframework/security/oauth2/provider/error/OAuth2AuthenticationEntryPoint.java new file mode 100644 index 000000000..622034692 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/error/OAuth2AuthenticationEntryPoint.java @@ -0,0 +1,86 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.provider.error; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.util.StringUtils; + +/** + * If authentication fails and the caller has asked for a specific content type response, this entry point can send one, + * along with a standard 401 status. Add to the Spring Security configuration as an {@link AuthenticationEntryPoint} in + * the usual way. + * + *

+ * + * @author Dave Syer + * + */ +public class OAuth2AuthenticationEntryPoint extends AbstractOAuth2SecurityExceptionHandler implements + AuthenticationEntryPoint { + + private String typeName = OAuth2AccessToken.BEARER_TYPE; + + private String realmName = "oauth"; + + public void setRealmName(String realmName) { + this.realmName = realmName; + } + + public void setTypeName(String typeName) { + this.typeName = typeName; + } + + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) + throws IOException, ServletException { + doHandle(request, response, authException); + } + + @Override + protected ResponseEntity enhanceResponse(ResponseEntity response, Exception exception) { + HttpHeaders headers = response.getHeaders(); + String existing = null; + if (headers.containsKey("WWW-Authenticate")) { + existing = extractTypePrefix(headers.getFirst("WWW-Authenticate")); + } + StringBuilder builder = new StringBuilder(); + builder.append(typeName+" "); + builder.append("realm=\"" + realmName + "\""); + if (existing!=null) { + builder.append(", "+existing); + } + HttpHeaders update = new HttpHeaders(); + update.putAll(response.getHeaders()); + update.set("WWW-Authenticate", builder.toString()); + return new ResponseEntity(response.getBody(), update, response.getStatusCode()); + } + + private String extractTypePrefix(String header) { + String existing = header; + String[] tokens = existing.split(" +"); + if (tokens.length > 1 && !tokens[0].endsWith(",")) { + existing = StringUtils.arrayToDelimitedString(tokens, " ").substring(existing.indexOf(" ") + 1); + } + return existing; + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/error/OAuth2ExceptionRenderer.java b/src/main/java/org/springframework/security/oauth2/provider/error/OAuth2ExceptionRenderer.java new file mode 100644 index 000000000..cc2e5649c --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/error/OAuth2ExceptionRenderer.java @@ -0,0 +1,30 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.provider.error; + +import org.springframework.http.HttpEntity; +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; +import org.springframework.web.context.request.ServletWebRequest; + +/** + * Strategy for rendering a {@link OAuth2Exception} in cases where they cannot be rendered by the Spring dispatcher + * servlet (i.e. usually in a filter chain). + * + *

+ * + * @author Dave Syer + * + */ +public interface OAuth2ExceptionRenderer { + void handleHttpEntityResponse(HttpEntity responseEntity, ServletWebRequest webRequest) throws Exception; +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/error/WebResponseExceptionTranslator.java b/src/main/java/org/springframework/security/oauth2/provider/error/WebResponseExceptionTranslator.java new file mode 100644 index 000000000..90bc426f3 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/error/WebResponseExceptionTranslator.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.oauth2.provider.error; + +import org.springframework.http.ResponseEntity; + +/** + * Translates exceptions into HTTP Responses. + * + * @param The error model that will be used as the HTTP Response body. + * + *

+ * + */ +public interface WebResponseExceptionTranslator { + + ResponseEntity translate(Exception e) throws Exception; + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/implicit/ImplicitTokenRequest.java b/src/main/java/org/springframework/security/oauth2/provider/implicit/ImplicitTokenRequest.java new file mode 100644 index 000000000..87aea3153 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/implicit/ImplicitTokenRequest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springframework.security.oauth2.provider.implicit; + +import org.springframework.security.oauth2.provider.OAuth2Request; +import org.springframework.security.oauth2.provider.TokenRequest; + +/** + *

+ * + * @author Dave Syer + * + * @since 2.0.2 + * + */ +@SuppressWarnings("serial") +public class ImplicitTokenRequest extends TokenRequest { + + private OAuth2Request oauth2Request; + + public ImplicitTokenRequest(TokenRequest tokenRequest, OAuth2Request oauth2Request) { + super(tokenRequest.getRequestParameters(), tokenRequest.getClientId(), tokenRequest.getScope(), tokenRequest.getGrantType()); + this.oauth2Request = oauth2Request; + } + + public OAuth2Request getOAuth2Request() { + return oauth2Request; + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/token/AuthenticationKeyGenerator.java b/src/main/java/org/springframework/security/oauth2/provider/token/AuthenticationKeyGenerator.java new file mode 100644 index 000000000..469036798 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/token/AuthenticationKeyGenerator.java @@ -0,0 +1,33 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.provider.token; + +import org.springframework.security.oauth2.provider.OAuth2Authentication; + +/** + * Strategy interface for extracting a unique key from an {@link OAuth2Authentication}. + * + *

+ * + * @author Dave Syer + * + */ +public interface AuthenticationKeyGenerator { + + /** + * @param authentication an OAuth2Authentication + * @return a unique key identifying the authentication + */ + String extractKey(OAuth2Authentication authentication); + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/token/AuthorizationServerTokenServices.java b/src/main/java/org/springframework/security/oauth2/provider/token/AuthorizationServerTokenServices.java new file mode 100644 index 000000000..1cc54e167 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/token/AuthorizationServerTokenServices.java @@ -0,0 +1,62 @@ +/* + * Copyright 2008 Web Cohesion + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.provider.token; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.TokenRequest; + +/** + *

+ * + * @author Ryan Heaton + * @author Dave Syer + */ +public interface AuthorizationServerTokenServices { + + /** + * Create an access token associated with the specified credentials. + * @param authentication The credentials associated with the access token. + * @return The access token. + * @throws AuthenticationException If the credentials are inadequate. + */ + OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException; + + /** + * Refresh an access token. The authorization request should be used for 2 things (at least): to validate that the + * client id of the original access token is the same as the one requesting the refresh, and to narrow the scopes + * (if provided). + * + * @param refreshToken The details about the refresh token. + * @param tokenRequest The incoming token request. + * @return The (new) access token. + * @throws AuthenticationException If the refresh token is invalid or expired. + */ + OAuth2AccessToken refreshAccessToken(String refreshToken, TokenRequest tokenRequest) + throws AuthenticationException; + + /** + * Retrieve an access token stored against the provided authentication key, if it exists. + * + * @param authentication the authentication key for the access token + * + * @return the access token or null if there was none + */ + OAuth2AccessToken getAccessToken(OAuth2Authentication authentication); + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/provider/token/ConsumerTokenServices.java b/src/main/java/org/springframework/security/oauth2/provider/token/ConsumerTokenServices.java new file mode 100644 index 000000000..2da665379 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/token/ConsumerTokenServices.java @@ -0,0 +1,26 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.provider.token; + + +/** + *

+ * + * @author Dave Syer + * + */ +public interface ConsumerTokenServices { + + boolean revokeToken(String tokenValue); + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/token/DefaultAuthenticationKeyGenerator.java b/src/main/java/org/springframework/security/oauth2/provider/token/DefaultAuthenticationKeyGenerator.java new file mode 100644 index 000000000..15fe3a0ab --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/token/DefaultAuthenticationKeyGenerator.java @@ -0,0 +1,69 @@ +/* + * Copyright 2006-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.provider.token; + +import org.springframework.security.oauth2.common.util.OAuth2Utils; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.OAuth2Request; + +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeSet; + +/** + * Basic key generator taking into account the client id, scope, resource ids and username (principal name) if they + * exist. + * + *

+ * + * @author Dave Syer + * + */ +public class DefaultAuthenticationKeyGenerator implements AuthenticationKeyGenerator { + + private static final String CLIENT_ID = "client_id"; + + private static final String SCOPE = "scope"; + + private static final String USERNAME = "username"; + + public String extractKey(OAuth2Authentication authentication) { + Map values = new LinkedHashMap(); + OAuth2Request authorizationRequest = authentication.getOAuth2Request(); + if (!authentication.isClientOnly()) { + values.put(USERNAME, authentication.getName()); + } + values.put(CLIENT_ID, authorizationRequest.getClientId()); + if (authorizationRequest.getScope() != null) { + values.put(SCOPE, OAuth2Utils.formatParameterList(new TreeSet(authorizationRequest.getScope()))); + } + return generateKey(values); + } + + protected String generateKey(Map values) { + MessageDigest digest; + try { + digest = MessageDigest.getInstance("MD5"); + byte[] bytes = digest.digest(values.toString().getBytes("UTF-8")); + return String.format("%032x", new BigInteger(1, bytes)); + } catch (NoSuchAlgorithmException nsae) { + throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK).", nsae); + } catch (UnsupportedEncodingException uee) { + throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).", uee); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/provider/token/ResourceServerTokenServices.java b/src/main/java/org/springframework/security/oauth2/provider/token/ResourceServerTokenServices.java new file mode 100644 index 000000000..8a55e4871 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/token/ResourceServerTokenServices.java @@ -0,0 +1,32 @@ +package org.springframework.security.oauth2.provider.token; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; +import org.springframework.security.oauth2.provider.OAuth2Authentication; + +/** + *

+ * + */ +public interface ResourceServerTokenServices { + + /** + * Load the credentials for the specified access token. + * + * @param accessToken The access token value. + * @return The authentication for the access token. + * @throws AuthenticationException If the access token is expired + * @throws InvalidTokenException if the token isn't valid + */ + OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException; + + /** + * Retrieve the full access token details from just the value. + * + * @param accessToken the token value + * @return the full access token with client id etc. + */ + OAuth2AccessToken readAccessToken(String accessToken); + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/security/oauth2/provider/token/TokenEnhancer.java b/src/main/java/org/springframework/security/oauth2/provider/token/TokenEnhancer.java new file mode 100644 index 000000000..b0a13b8a1 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/token/TokenEnhancer.java @@ -0,0 +1,39 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.provider.token; + +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.OAuth2Authentication; + +/** + * Strategy for enhancing an access token before it is stored by an {@link AuthorizationServerTokenServices} + * implementation. + * + *

+ * + * @author Dave Syer + * + */ +public interface TokenEnhancer { + + /** + * Provides an opportunity for customization of an access token (e.g. through its additional information map) during + * the process of creating a new token for use by a client. + * + * @param accessToken the current access token with its expiration and refresh token + * @param authentication the current authentication including client and user details + * @return a new token enhanced with additional information + */ + OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication); + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/token/TokenEnhancerChain.java b/src/main/java/org/springframework/security/oauth2/provider/token/TokenEnhancerChain.java new file mode 100644 index 000000000..d609a1a77 --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/token/TokenEnhancerChain.java @@ -0,0 +1,54 @@ +/* + * Copyright 2006-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.oauth2.provider.token; + +import java.util.Collections; +import java.util.List; + +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.OAuth2Authentication; + +/** + * A composite token enhancer that loops over its delegate enhancers. + * + *

+ * + * @author Dave Syer + * + */ +public class TokenEnhancerChain implements TokenEnhancer { + + private List delegates = Collections.emptyList(); + + /** + * @param delegates the delegates to set + */ + public void setTokenEnhancers(List delegates) { + this.delegates = delegates; + } + + /** + * Loop over the {@link #setTokenEnhancers(List) delegates} passing the result into the next member of the chain. + * + * @see org.springframework.security.oauth2.provider.token.TokenEnhancer#enhance(org.springframework.security.oauth2.common.OAuth2AccessToken, + * org.springframework.security.oauth2.provider.OAuth2Authentication) + */ + public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { + OAuth2AccessToken result = accessToken; + for (TokenEnhancer enhancer : delegates) { + result = enhancer.enhance(result, authentication); + } + return result; + } + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/token/TokenStore.java b/src/main/java/org/springframework/security/oauth2/provider/token/TokenStore.java new file mode 100644 index 000000000..4c081194f --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/token/TokenStore.java @@ -0,0 +1,115 @@ +package org.springframework.security.oauth2.provider.token; + +import java.util.Collection; + +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.common.OAuth2RefreshToken; +import org.springframework.security.oauth2.provider.OAuth2Authentication; + +/** + * Persistence interface for OAuth2 tokens. + * + *

+ * + */ +public interface TokenStore { + + /** + * Read the authentication stored under the specified token value. + * + * @param token The token value under which the authentication is stored. + * @return The authentication, or null if none. + */ + OAuth2Authentication readAuthentication(OAuth2AccessToken token); + + /** + * Read the authentication stored under the specified token value. + * + * @param token The token value under which the authentication is stored. + * @return The authentication, or null if none. + */ + OAuth2Authentication readAuthentication(String token); + + /** + * Store an access token. + * + * @param token The token to store. + * @param authentication The authentication associated with the token. + */ + void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication); + + /** + * Read an access token from the store. + * + * @param tokenValue The token value. + * @return The access token to read. + */ + OAuth2AccessToken readAccessToken(String tokenValue); + + /** + * Remove an access token from the store. + * + * @param token The token to remove from the store. + */ + void removeAccessToken(OAuth2AccessToken token); + + /** + * Store the specified refresh token in the store. + * + * @param refreshToken The refresh token to store. + * @param authentication The authentication associated with the refresh token. + */ + void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication); + + /** + * Read a refresh token from the store. + * + * @param tokenValue The value of the token to read. + * @return The token. + */ + OAuth2RefreshToken readRefreshToken(String tokenValue); + + /** + * @param token a refresh token + * @return the authentication originally used to grant the refresh token + */ + OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token); + + /** + * Remove a refresh token from the store. + * + * @param token The token to remove from the store. + */ + void removeRefreshToken(OAuth2RefreshToken token); + + /** + * Remove an access token using a refresh token. This functionality is necessary so refresh tokens can't be used to + * create an unlimited number of access tokens. + * + * @param refreshToken The refresh token. + */ + void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken); + + /** + * Retrieve an access token stored against the provided authentication key, if it exists. + * + * @param authentication the authentication key for the access token + * + * @return the access token or null if there was none + */ + OAuth2AccessToken getAccessToken(OAuth2Authentication authentication); + + /** + * @param clientId the client id to search + * @param userName the user name to search + * @return a collection of access tokens + */ + Collection findTokensByClientIdAndUserName(String clientId, String userName); + + /** + * @param clientId the client id to search + * @return a collection of access tokens + */ + Collection findTokensByClientId(String clientId); + +} diff --git a/src/main/java/org/springframework/security/oauth2/provider/token/store/JdbcTokenStore.java b/src/main/java/org/springframework/security/oauth2/provider/token/store/JdbcTokenStore.java new file mode 100644 index 000000000..2f837c4be --- /dev/null +++ b/src/main/java/org/springframework/security/oauth2/provider/token/store/JdbcTokenStore.java @@ -0,0 +1,464 @@ +package org.springframework.security.oauth2.provider.token.store; + +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.sql.DataSource; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.support.SqlLobValue; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.common.OAuth2RefreshToken; +import org.springframework.security.oauth2.common.util.SerializationUtils; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.token.AuthenticationKeyGenerator; +import org.springframework.security.oauth2.provider.token.DefaultAuthenticationKeyGenerator; +import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.util.Assert; + +/** + * Implementation of token services that stores tokens in a database. + * + *

+ * + * @author Ken Dombeck + * @author Luke Taylor + * @author Dave Syer + */ +public class JdbcTokenStore implements TokenStore { + + private static final Log LOG = LogFactory.getLog(JdbcTokenStore.class); + + private static final String DEFAULT_ACCESS_TOKEN_INSERT_STATEMENT = "insert into oauth_access_token (token_id, token, authentication_id, user_name, client_id, authentication, refresh_token) values (?, ?, ?, ?, ?, ?, ?)"; + + private static final String DEFAULT_ACCESS_TOKEN_SELECT_STATEMENT = "select token_id, token from oauth_access_token where token_id = ?"; + + private static final String DEFAULT_ACCESS_TOKEN_AUTHENTICATION_SELECT_STATEMENT = "select token_id, authentication from oauth_access_token where token_id = ?"; + + private static final String DEFAULT_ACCESS_TOKEN_FROM_AUTHENTICATION_SELECT_STATEMENT = "select token_id, token from oauth_access_token where authentication_id = ?"; + + private static final String DEFAULT_ACCESS_TOKENS_FROM_USERNAME_AND_CLIENT_SELECT_STATEMENT = "select token_id, token from oauth_access_token where user_name = ? and client_id = ?"; + + private static final String DEFAULT_ACCESS_TOKENS_FROM_USERNAME_SELECT_STATEMENT = "select token_id, token from oauth_access_token where user_name = ?"; + + private static final String DEFAULT_ACCESS_TOKENS_FROM_CLIENTID_SELECT_STATEMENT = "select token_id, token from oauth_access_token where client_id = ?"; + + private static final String DEFAULT_ACCESS_TOKEN_DELETE_STATEMENT = "delete from oauth_access_token where token_id = ?"; + + private static final String DEFAULT_ACCESS_TOKEN_DELETE_FROM_REFRESH_TOKEN_STATEMENT = "delete from oauth_access_token where refresh_token = ?"; + + private static final String DEFAULT_REFRESH_TOKEN_INSERT_STATEMENT = "insert into oauth_refresh_token (token_id, token, authentication) values (?, ?, ?)"; + + private static final String DEFAULT_REFRESH_TOKEN_SELECT_STATEMENT = "select token_id, token from oauth_refresh_token where token_id = ?"; + + private static final String DEFAULT_REFRESH_TOKEN_AUTHENTICATION_SELECT_STATEMENT = "select token_id, authentication from oauth_refresh_token where token_id = ?"; + + private static final String DEFAULT_REFRESH_TOKEN_DELETE_STATEMENT = "delete from oauth_refresh_token where token_id = ?"; + + private String insertAccessTokenSql = DEFAULT_ACCESS_TOKEN_INSERT_STATEMENT; + + private String selectAccessTokenSql = DEFAULT_ACCESS_TOKEN_SELECT_STATEMENT; + + private String selectAccessTokenAuthenticationSql = DEFAULT_ACCESS_TOKEN_AUTHENTICATION_SELECT_STATEMENT; + + private String selectAccessTokenFromAuthenticationSql = DEFAULT_ACCESS_TOKEN_FROM_AUTHENTICATION_SELECT_STATEMENT; + + private String selectAccessTokensFromUserNameAndClientIdSql = DEFAULT_ACCESS_TOKENS_FROM_USERNAME_AND_CLIENT_SELECT_STATEMENT; + + private String selectAccessTokensFromUserNameSql = DEFAULT_ACCESS_TOKENS_FROM_USERNAME_SELECT_STATEMENT; + + private String selectAccessTokensFromClientIdSql = DEFAULT_ACCESS_TOKENS_FROM_CLIENTID_SELECT_STATEMENT; + + private String deleteAccessTokenSql = DEFAULT_ACCESS_TOKEN_DELETE_STATEMENT; + + private String insertRefreshTokenSql = DEFAULT_REFRESH_TOKEN_INSERT_STATEMENT; + + private String selectRefreshTokenSql = DEFAULT_REFRESH_TOKEN_SELECT_STATEMENT; + + private String selectRefreshTokenAuthenticationSql = DEFAULT_REFRESH_TOKEN_AUTHENTICATION_SELECT_STATEMENT; + + private String deleteRefreshTokenSql = DEFAULT_REFRESH_TOKEN_DELETE_STATEMENT; + + private String deleteAccessTokenFromRefreshTokenSql = DEFAULT_ACCESS_TOKEN_DELETE_FROM_REFRESH_TOKEN_STATEMENT; + + private AuthenticationKeyGenerator authenticationKeyGenerator = new DefaultAuthenticationKeyGenerator(); + + private final JdbcTemplate jdbcTemplate; + + public JdbcTokenStore(DataSource dataSource) { + Assert.notNull(dataSource, "DataSource required"); + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + public void setAuthenticationKeyGenerator(AuthenticationKeyGenerator authenticationKeyGenerator) { + this.authenticationKeyGenerator = authenticationKeyGenerator; + } + + public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) { + OAuth2AccessToken accessToken = null; + + String key = authenticationKeyGenerator.extractKey(authentication); + try { + accessToken = jdbcTemplate.queryForObject(selectAccessTokenFromAuthenticationSql, + new RowMapper() { + public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException { + return deserializeAccessToken(rs.getBytes(2)); + } + }, key); + } + catch (EmptyResultDataAccessException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Failed to find access token for authentication " + authentication); + } + } + catch (IllegalArgumentException e) { + LOG.error("Could not extract access token for authentication " + authentication, e); + } + + if (accessToken != null) { + OAuth2Authentication oldAuthentication = readAuthentication(accessToken.getValue()); + if (oldAuthentication == null || !key.equals(authenticationKeyGenerator.extractKey(oldAuthentication))) { + removeAccessToken(accessToken.getValue()); + // Keep the store consistent (maybe the same user is represented by this authentication but the details have + // changed) + storeAccessToken(accessToken, authentication); + } + } + return accessToken; + } + + public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) { + String refreshToken = null; + if (token.getRefreshToken() != null) { + refreshToken = token.getRefreshToken().getValue(); + } + + if (readAccessToken(token.getValue())!=null) { + removeAccessToken(token.getValue()); + } + + jdbcTemplate.update(insertAccessTokenSql, new Object[] { extractTokenKey(token.getValue()), + new SqlLobValue(serializeAccessToken(token)), authenticationKeyGenerator.extractKey(authentication), + authentication.isClientOnly() ? null : authentication.getName(), + authentication.getOAuth2Request().getClientId(), + new SqlLobValue(serializeAuthentication(authentication)), extractTokenKey(refreshToken) }, new int[] { + Types.VARCHAR, Types.BLOB, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.BLOB, Types.VARCHAR }); + } + + public OAuth2AccessToken readAccessToken(String tokenValue) { + OAuth2AccessToken accessToken = null; + + try { + accessToken = jdbcTemplate.queryForObject(selectAccessTokenSql, new RowMapper() { + public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException { + return deserializeAccessToken(rs.getBytes(2)); + } + }, extractTokenKey(tokenValue)); + } + catch (EmptyResultDataAccessException e) { + if (LOG.isInfoEnabled()) { + LOG.info("Failed to find access token"); + } + } + catch (IllegalArgumentException e) { + LOG.warn("Failed to deserialize access token", e); + removeAccessToken(tokenValue); + } + + return accessToken; + } + + public void removeAccessToken(OAuth2AccessToken token) { + removeAccessToken(token.getValue()); + } + + public void removeAccessToken(String tokenValue) { + jdbcTemplate.update(deleteAccessTokenSql, extractTokenKey(tokenValue)); + } + + public OAuth2Authentication readAuthentication(OAuth2AccessToken token) { + return readAuthentication(token.getValue()); + } + + public OAuth2Authentication readAuthentication(String token) { + OAuth2Authentication authentication = null; + + try { + authentication = jdbcTemplate.queryForObject(selectAccessTokenAuthenticationSql, + new RowMapper() { + public OAuth2Authentication mapRow(ResultSet rs, int rowNum) throws SQLException { + return deserializeAuthentication(rs.getBytes(2)); + } + }, extractTokenKey(token)); + } + catch (EmptyResultDataAccessException e) { + if (LOG.isInfoEnabled()) { + LOG.info("Failed to find access token"); + } + } + catch (IllegalArgumentException e) { + LOG.warn("Failed to deserialize authentication", e); + removeAccessToken(token); + } + + return authentication; + } + + public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) { + jdbcTemplate.update(insertRefreshTokenSql, new Object[] { extractTokenKey(refreshToken.getValue()), + new SqlLobValue(serializeRefreshToken(refreshToken)), + new SqlLobValue(serializeAuthentication(authentication)) }, new int[] { Types.VARCHAR, Types.BLOB, + Types.BLOB }); + } + + public OAuth2RefreshToken readRefreshToken(String token) { + OAuth2RefreshToken refreshToken = null; + + try { + refreshToken = jdbcTemplate.queryForObject(selectRefreshTokenSql, new RowMapper() { + public OAuth2RefreshToken mapRow(ResultSet rs, int rowNum) throws SQLException { + return deserializeRefreshToken(rs.getBytes(2)); + } + }, extractTokenKey(token)); + } + catch (EmptyResultDataAccessException e) { + if (LOG.isInfoEnabled()) { + LOG.info("Failed to find refresh token"); + } + } + catch (IllegalArgumentException e) { + LOG.warn("Failed to deserialize refresh token", e); + removeRefreshToken(token); + } + + return refreshToken; + } + + public void removeRefreshToken(OAuth2RefreshToken token) { + removeRefreshToken(token.getValue()); + } + + public void removeRefreshToken(String token) { + jdbcTemplate.update(deleteRefreshTokenSql, extractTokenKey(token)); + } + + public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token) { + return readAuthenticationForRefreshToken(token.getValue()); + } + + public OAuth2Authentication readAuthenticationForRefreshToken(String value) { + OAuth2Authentication authentication = null; + + try { + authentication = jdbcTemplate.queryForObject(selectRefreshTokenAuthenticationSql, + new RowMapper() { + public OAuth2Authentication mapRow(ResultSet rs, int rowNum) throws SQLException { + return deserializeAuthentication(rs.getBytes(2)); + } + }, extractTokenKey(value)); + } + catch (EmptyResultDataAccessException e) { + if (LOG.isInfoEnabled()) { + LOG.info("Failed to find access token"); + } + } + catch (IllegalArgumentException e) { + LOG.warn("Failed to deserialize access token", e); + removeRefreshToken(value); + } + + return authentication; + } + + public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) { + removeAccessTokenUsingRefreshToken(refreshToken.getValue()); + } + + public void removeAccessTokenUsingRefreshToken(String refreshToken) { + jdbcTemplate.update(deleteAccessTokenFromRefreshTokenSql, new Object[] { extractTokenKey(refreshToken) }, + new int[] { Types.VARCHAR }); + } + + public Collection findTokensByClientId(String clientId) { + List accessTokens = new ArrayList(); + + try { + accessTokens = jdbcTemplate.query(selectAccessTokensFromClientIdSql, new SafeAccessTokenRowMapper(), + clientId); + } + catch (EmptyResultDataAccessException e) { + if (LOG.isInfoEnabled()) { + LOG.info("Failed to find access token for clientId " + clientId); + } + } + accessTokens = removeNulls(accessTokens); + + return accessTokens; + } + + public Collection findTokensByUserName(String userName) { + List accessTokens = new ArrayList(); + + try { + accessTokens = jdbcTemplate.query(selectAccessTokensFromUserNameSql, new SafeAccessTokenRowMapper(), + userName); + } + catch (EmptyResultDataAccessException e) { + if (LOG.isInfoEnabled()) + LOG.info("Failed to find access token for userName " + userName); + } + accessTokens = removeNulls(accessTokens); + + return accessTokens; + } + + public Collection findTokensByClientIdAndUserName(String clientId, String userName) { + List accessTokens = new ArrayList(); + + try { + accessTokens = jdbcTemplate.query(selectAccessTokensFromUserNameAndClientIdSql, new SafeAccessTokenRowMapper(), + userName, clientId); + } + catch (EmptyResultDataAccessException e) { + if (LOG.isInfoEnabled()) { + LOG.info("Failed to find access token for clientId " + clientId + " and userName " + userName); + } + } + accessTokens = removeNulls(accessTokens); + + return accessTokens; + } + + private List removeNulls(List accessTokens) { + List tokens = new ArrayList(); + for (OAuth2AccessToken token : accessTokens) { + if (token != null) { + tokens.add(token); + } + } + return tokens; + } + + protected String extractTokenKey(String value) { + if (value == null) { + return null; + } + MessageDigest digest; + try { + digest = MessageDigest.getInstance("MD5"); + } + catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK)."); + } + + try { + byte[] bytes = digest.digest(value.getBytes("UTF-8")); + return String.format("%032x", new BigInteger(1, bytes)); + } + catch (UnsupportedEncodingException e) { + throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK)."); + } + } + + private final class SafeAccessTokenRowMapper implements RowMapper { + public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException { + try { + return deserializeAccessToken(rs.getBytes(2)); + } + catch (IllegalArgumentException e) { + String token = rs.getString(1); + jdbcTemplate.update(deleteAccessTokenSql, token); + return null; + } + } + } + + protected byte[] serializeAccessToken(OAuth2AccessToken token) { + return SerializationUtils.serialize(token); + } + + protected byte[] serializeRefreshToken(OAuth2RefreshToken token) { + return SerializationUtils.serialize(token); + } + + protected byte[] serializeAuthentication(OAuth2Authentication authentication) { + return SerializationUtils.serialize(authentication); + } + + protected OAuth2AccessToken deserializeAccessToken(byte[] token) { + return SerializationUtils.deserialize(token); + } + + protected OAuth2RefreshToken deserializeRefreshToken(byte[] token) { + return SerializationUtils.deserialize(token); + } + + protected OAuth2Authentication deserializeAuthentication(byte[] authentication) { + return SerializationUtils.deserialize(authentication); + } + + public void setInsertAccessTokenSql(String insertAccessTokenSql) { + this.insertAccessTokenSql = insertAccessTokenSql; + } + + public void setSelectAccessTokenSql(String selectAccessTokenSql) { + this.selectAccessTokenSql = selectAccessTokenSql; + } + + public void setDeleteAccessTokenSql(String deleteAccessTokenSql) { + this.deleteAccessTokenSql = deleteAccessTokenSql; + } + + public void setInsertRefreshTokenSql(String insertRefreshTokenSql) { + this.insertRefreshTokenSql = insertRefreshTokenSql; + } + + public void setSelectRefreshTokenSql(String selectRefreshTokenSql) { + this.selectRefreshTokenSql = selectRefreshTokenSql; + } + + public void setDeleteRefreshTokenSql(String deleteRefreshTokenSql) { + this.deleteRefreshTokenSql = deleteRefreshTokenSql; + } + + public void setSelectAccessTokenAuthenticationSql(String selectAccessTokenAuthenticationSql) { + this.selectAccessTokenAuthenticationSql = selectAccessTokenAuthenticationSql; + } + + public void setSelectRefreshTokenAuthenticationSql(String selectRefreshTokenAuthenticationSql) { + this.selectRefreshTokenAuthenticationSql = selectRefreshTokenAuthenticationSql; + } + + public void setSelectAccessTokenFromAuthenticationSql(String selectAccessTokenFromAuthenticationSql) { + this.selectAccessTokenFromAuthenticationSql = selectAccessTokenFromAuthenticationSql; + } + + public void setDeleteAccessTokenFromRefreshTokenSql(String deleteAccessTokenFromRefreshTokenSql) { + this.deleteAccessTokenFromRefreshTokenSql = deleteAccessTokenFromRefreshTokenSql; + } + + public void setSelectAccessTokensFromUserNameSql(String selectAccessTokensFromUserNameSql) { + this.selectAccessTokensFromUserNameSql = selectAccessTokensFromUserNameSql; + } + + public void setSelectAccessTokensFromUserNameAndClientIdSql(String selectAccessTokensFromUserNameAndClientIdSql) { + this.selectAccessTokensFromUserNameAndClientIdSql = selectAccessTokensFromUserNameAndClientIdSql; + } + + public void setSelectAccessTokensFromClientIdSql(String selectAccessTokensFromClientIdSql) { + this.selectAccessTokensFromClientIdSql = selectAccessTokensFromClientIdSql; + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e37615014..505867991 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -59,7 +59,7 @@ security: origins: "*" console: cors: - origins: + origins: ${CORS_CONSOLE_ORIGINS:} webauthn: id: origins: @@ -87,8 +87,10 @@ oauth2: allowRefresh: ${OAUTH2_RESOURCEOWNERPASSWORD_ALLOW_REFRESH:true} accesstoken: validity: ${ACCESS_TOKEN_VALIDITY:43200} + cleanup: ${ACCESS_TOKEN_VALIDITY:2592000} refreshtoken: validity: ${REFRESH_TOKEN_VALIDITY:2592000} + cleanup: ${ACCESS_TOKEN_VALIDITY:2592000} authcode: validity: ${AUTH_CODE_VALIDITY:600} @@ -108,6 +110,20 @@ audit: kid: sig: ${AUDIT_KID_SIG:} enc: ${AUDIT_KID_ENC:} + jdbc: + dialect: ${AUDIT_JDBC_DIALECT:${jdbc.dialect}} + driver: ${AUDIT_JDBC_DRIVER:${jdbc.driver}} + url: ${AUDIT_JDBC_URL:${jdbc.url}} + user: ${AUDIT_JDBC_USER:${jdbc.user}} + password: ${AUDIT_JDBC_PASS:${jdbc.password}} + show-sql: false + initialize-schema: always + max-pool-size: ${AUDIT_JDBC_MAX_POOL_SIZE:${jdbc.maxpoolsize}} + min-pool-size: ${AUDIT_JDBC_MIN_POOL_SIZE:${jdbc.minpoolsize}} + idle-timeout: ${AUDIT_JDBC_IDLE_TIMEOUT:${jdbc.idletimeout}} + keep-alive-timeout: ${AUDIT_JDBC_KEEP_ALIVE_TIMEOUT:${jdbc.keepalivetimeout}} + connection-timeout: ${AUDIT_JDBC_CONNECTION_TIMEOUT:${jdbc.connectiontimeout}} + data-source-properties: {} #EXTERNAL PROVIDERS authorities: @@ -291,11 +307,6 @@ spid: entityLabel: timid metadataUrl: https://login.id.tim.it/spid-services/MetadataBrowser/idp iconUrl: /spid/img/spid-idp-timid.svg - - entityName: Spid Validator - entityId: https://localhost:8443 - entityLabel: spidvalidator - metadataUrl: https://localhost:8443/metadata.xml - iconUrl: /spid/img/spid-ico-circle-bb.svg attributesets: sets: @@ -372,12 +383,15 @@ management: enabled-by-default: false web: base-path: - exposure.include: "health,info" + exposure: + include: "health,info,metrics" endpoint: info: enabled: true health: enabled: true + metrics: + enabled: true # Open API diff --git a/src/main/resources/db/sql/oauth2/schema-h2.sql b/src/main/resources/db/sql/oauth2/schema-h2.sql index 48c24f0e5..66d20a7cc 100644 --- a/src/main/resources/db/sql/oauth2/schema-h2.sql +++ b/src/main/resources/db/sql/oauth2/schema-h2.sql @@ -23,6 +23,8 @@ CREATE TABLE authentication_id VARCHAR(256), user_name VARCHAR(256), client_id VARCHAR(256), + issued_at datetime DEFAULT NULL, + expires_at datetime DEFAULT NULL, authentication BLOB, refresh_token VARCHAR(256) ); @@ -31,5 +33,10 @@ CREATE TABLE IF NOT EXISTS oauth_refresh_token ( token_id VARCHAR(64) NOT NULL PRIMARY KEY, token BLOB NOT NULL, + authentication_id VARCHAR(256), + user_name VARCHAR(256), + client_id VARCHAR(256), + issued_at datetime DEFAULT NULL, + expires_at datetime DEFAULT NULL, authentication BLOB NOT NULL ); \ No newline at end of file diff --git a/src/main/resources/db/sql/oauth2/schema-mysql.sql b/src/main/resources/db/sql/oauth2/schema-mysql.sql index a6c091954..93f2e4680 100644 --- a/src/main/resources/db/sql/oauth2/schema-mysql.sql +++ b/src/main/resources/db/sql/oauth2/schema-mysql.sql @@ -23,6 +23,8 @@ CREATE TABLE authentication_id VARCHAR(256), user_name VARCHAR(256), client_id VARCHAR(256), + issuet_at datetime DEFAULT NULL, + expires_at datetime DEFAULT NULL, authentication BLOB, refresh_token VARCHAR(256) ) ENGINE = InnoDB ROW_FORMAT = DYNAMIC; @@ -31,6 +33,11 @@ CREATE TABLE IF NOT EXISTS oauth_refresh_token ( token_id VARCHAR(64) NOT NULL PRIMARY KEY, token BLOB NOT NULL, + authentication_id VARCHAR(256), + user_name VARCHAR(256), + client_id VARCHAR(256), + issuet_at datetime DEFAULT NULL, + expires_at datetime DEFAULT NULL, authentication BLOB NOT NULL ) ENGINE = InnoDB ROW_FORMAT = DYNAMIC; @@ -39,4 +46,6 @@ CREATE INDEX oauth_access_token_token_user_index ON oauth_access_token (user_nam CREATE INDEX oauth_access_token_token_client_index ON oauth_access_token (client_id); CREATE INDEX oauth_access_token_token_refresh_token_index ON oauth_access_token (refresh_token); -CREATE INDEX oauth_refresh_token_token_id_index ON oauth_refresh_token (token_id); \ No newline at end of file +CREATE INDEX oauth_refresh_token_token_id_index ON oauth_refresh_token (token_id); +CREATE INDEX oauth_refresh_token_token_user_index ON oauth_refresh_token (user_name); +CREATE INDEX oauth_refresh_token_token_client_index ON oauth_refresh_token (client_id); \ No newline at end of file diff --git a/src/main/resources/db/sql/oauth2/schema-postgresql.sql b/src/main/resources/db/sql/oauth2/schema-postgresql.sql index 5a27df63c..b9908be8f 100644 --- a/src/main/resources/db/sql/oauth2/schema-postgresql.sql +++ b/src/main/resources/db/sql/oauth2/schema-postgresql.sql @@ -23,6 +23,8 @@ CREATE TABLE authentication_id VARCHAR(256), user_name VARCHAR(256), client_id VARCHAR(256), + issued_at timestamp DEFAULT NULL, + expires_at timestamp DEFAULT NULL, authentication bytea, refresh_token VARCHAR(256) ); @@ -31,6 +33,11 @@ CREATE TABLE IF NOT EXISTS oauth_refresh_token ( token_id VARCHAR(64) NOT NULL PRIMARY KEY, token bytea NOT NULL, + authentication_id VARCHAR(256), + user_name VARCHAR(256), + client_id VARCHAR(256), + issued_at timestamp DEFAULT NULL, + expires_at timestamp DEFAULT NULL, authentication bytea NOT NULL ); @@ -39,4 +46,6 @@ CREATE INDEX oauth_access_token_token_user_index ON public.oauth_access_token (u CREATE INDEX oauth_access_token_token_client_index ON public.oauth_access_token (client_id); CREATE INDEX oauth_access_token_token_refresh_token_index ON public.oauth_access_token (refresh_token); -CREATE INDEX oauth_refresh_token_token_id_index ON public.oauth_refresh_token (token_id); \ No newline at end of file +CREATE INDEX oauth_refresh_token_token_id_index ON public.oauth_refresh_token (token_id); +CREATE INDEX oauth_refresh_token_token_user_index ON public.oauth_refresh_token (user_name); +CREATE INDEX oauth_refresh_token_token_client_index ON public.oauth_refresh_token (client_id); \ No newline at end of file diff --git a/src/main/resources/public/html/service/claims.html b/src/main/resources/public/html/service/claims.html index 6b9864c78..1ed21c3ff 100644 --- a/src/main/resources/public/html/service/claims.html +++ b/src/main/resources/public/html/service/claims.html @@ -85,28 +85,28 @@

+ ng-model="claimMappingUser.enabled" ng-change="toggleClaimMapping('user')">
-
+
-
+


+ ng-model="claimMappingUser.scopes">
-
+
-
{{claimMapping['user'].result | json:4}}
+
{{claimMappingUser.result | json:4}}
-
{{err}}
+
{{err}}
@@ -142,28 +142,28 @@
+ ng-model="claimMappingClient.enabled" ng-change="toggleClaimMapping('client')">
-
+
-
+


+ ng-model="claimMappingClient.scopes">
-
+
-
{{claimMapping['client'].result | json:4}}
+
{{claimMappingClient.result | json:4}}
-
{{err}} +
{{err}}
diff --git a/src/main/resources/public/js/realmaudit.js b/src/main/resources/public/js/realmaudit.js index c73709b85..0423b4f32 100644 --- a/src/main/resources/public/js/realmaudit.js +++ b/src/main/resources/public/js/realmaudit.js @@ -21,7 +21,7 @@ angular.module('aac.controllers.realmaudit', []) return $http.get('console/dev/audit/' + slug, { params: params }).then(function (data) { - return data.data; + return data.data.content; }); } @@ -51,7 +51,7 @@ angular.module('aac.controllers.realmaudit', []) params.size = 20; } - return $http.get('console/dev/audit/' + slug + '/search', { + return $http.get('console/dev/audit/' + slug , { params: params }).then(function (data) { return data.data; diff --git a/src/main/resources/public/js/realmgroups.js b/src/main/resources/public/js/realmgroups.js index ff4137c4f..a4990da26 100644 --- a/src/main/resources/public/js/realmgroups.js +++ b/src/main/resources/public/js/realmgroups.js @@ -4,8 +4,8 @@ angular.module('aac.controllers.realmgroups', []) var service = {}; service.getGroups = function (realm) { - return $http.get('console/dev/groups/' + realm).then(function (data) { - return data.data; + return $http.get('console/dev/groups/' + realm + '?page=0&size=200').then(function (data) { + return data.data.content; }); } service.getGroup = function (realm, groupId) { diff --git a/src/main/resources/public/js/realmproviders.js b/src/main/resources/public/js/realmproviders.js index 8fa8d7dda..06e99907a 100644 --- a/src/main/resources/public/js/realmproviders.js +++ b/src/main/resources/public/js/realmproviders.js @@ -34,8 +34,8 @@ angular.module('aac.controllers.realmproviders', []) } service.getIdentityProviders = function (slug) { - return $http.get('console/dev/idps/' + slug).then(function (data) { - return data.data; + return $http.get('console/dev/idps/' + slug+ '?page=0&size=200').then(function (data) { + return data.data.content; }); } diff --git a/src/main/resources/public/js/realmroles.js b/src/main/resources/public/js/realmroles.js index d17db790b..3fbd37131 100644 --- a/src/main/resources/public/js/realmroles.js +++ b/src/main/resources/public/js/realmroles.js @@ -4,8 +4,8 @@ angular.module('aac.controllers.realmroles', []) var service = {}; service.getRoles = function (realm) { - return $http.get('console/dev/roles/' + realm).then(function (data) { - return data.data; + return $http.get('console/dev/roles/' + realm + '?page=0&size=200').then(function (data) { + return data.data.content; }); } service.getRole = function (realm, roleId) { diff --git a/src/main/resources/templates/console/admin.html b/src/main/resources/templates/console/admin.html new file mode 100644 index 000000000..03100cbc9 --- /dev/null +++ b/src/main/resources/templates/console/admin.html @@ -0,0 +1,27 @@ + + + + + + + admin-console + + + + +
+
+
Loading...
+
+
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/console/dev.html b/src/main/resources/templates/console/dev.html new file mode 100644 index 000000000..a9039f61c --- /dev/null +++ b/src/main/resources/templates/console/dev.html @@ -0,0 +1,27 @@ + + + + + + + dh-console + + + + +
+
+
Loading...
+
+
+ + + + \ No newline at end of file diff --git a/src/test/java/it/smartcommunitylab/aac/tos/TosConfigTest.java b/src/test/java/it/smartcommunitylab/aac/tos/TosConfigTest.java index 096323b2c..220c3429b 100644 --- a/src/test/java/it/smartcommunitylab/aac/tos/TosConfigTest.java +++ b/src/test/java/it/smartcommunitylab/aac/tos/TosConfigTest.java @@ -85,7 +85,8 @@ public void tosConfigIsEnabled() throws Exception { realm.isPublic(), realm.getOAuthConfiguration().getConfiguration(), tosConfig.getConfiguration(), - null + realm.getLocalizationConfiguration().getConfiguration(), + realm.getTemplatesConfiguration().getConfiguration() ); //updated model shows 'enabled' @@ -110,7 +111,8 @@ public void tosConfigIsEnabled() throws Exception { realm.isPublic(), realm.getOAuthConfiguration().getConfiguration(), tosConfig.getConfiguration(), - null + realm.getLocalizationConfiguration().getConfiguration(), + realm.getTemplatesConfiguration().getConfiguration() ); //updated model shows 'disabled' @@ -150,7 +152,8 @@ public void tosConfigIsApproval() throws Exception { realm.isPublic(), realm.getOAuthConfiguration().getConfiguration(), tosConfig.getConfiguration(), - null + realm.getLocalizationConfiguration().getConfiguration(), + realm.getTemplatesConfiguration().getConfiguration() ); //updated model shows 'enabled' @@ -175,7 +178,8 @@ public void tosConfigIsApproval() throws Exception { realm.isPublic(), realm.getOAuthConfiguration().getConfiguration(), tosConfig.getConfiguration(), - null + realm.getLocalizationConfiguration().getConfiguration(), + realm.getTemplatesConfiguration().getConfiguration() ); //updated model shows 'disabled' @@ -249,7 +253,8 @@ private void updateTos(String slug, TosConfigurationMap configMap) throws NoSuch realm.isPublic(), realm.getOAuthConfiguration().getConfiguration(), configMap.getConfiguration(), - null + realm.getLocalizationConfiguration().getConfiguration(), + realm.getTemplatesConfiguration().getConfiguration() ); } diff --git a/src/test/java/it/smartcommunitylab/aac/tos/TosUserTest.java b/src/test/java/it/smartcommunitylab/aac/tos/TosUserTest.java index a026f1e40..7ca977136 100644 --- a/src/test/java/it/smartcommunitylab/aac/tos/TosUserTest.java +++ b/src/test/java/it/smartcommunitylab/aac/tos/TosUserTest.java @@ -262,7 +262,8 @@ private void updateTos(String slug, TosConfigurationMap configMap) throws NoSuch realm.isPublic(), realm.getOAuthConfiguration().getConfiguration(), configMap.getConfiguration(), - null + realm.getLocalizationConfiguration().getConfiguration(), + realm.getTemplatesConfiguration().getConfiguration() ); } diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..19082cc48 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,470 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.22.13": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.0.tgz#9374b5cd068d128dac0b94ff482594273b1c2815" + integrity sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +"@chevrotain/cst-dts-gen@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz#5e0863cc57dc45e204ccfee6303225d15d9d4783" + integrity sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ== + dependencies: + "@chevrotain/gast" "11.0.3" + "@chevrotain/types" "11.0.3" + lodash-es "4.17.21" + +"@chevrotain/gast@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/gast/-/gast-11.0.3.tgz#e84d8880323fe8cbe792ef69ce3ffd43a936e818" + integrity sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q== + dependencies: + "@chevrotain/types" "11.0.3" + lodash-es "4.17.21" + +"@chevrotain/regexp-to-ast@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz#11429a81c74a8e6a829271ce02fc66166d56dcdb" + integrity sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA== + +"@chevrotain/types@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/types/-/types-11.0.3.tgz#f8a03914f7b937f594f56eb89312b3b8f1c91848" + integrity sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ== + +"@chevrotain/utils@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/utils/-/utils-11.0.3.tgz#e39999307b102cff3645ec4f5b3665f5297a2224" + integrity sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ== + +"@conventional-changelog/git-client@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@conventional-changelog/git-client/-/git-client-1.0.1.tgz#143be2777ba389c3c14f83fa19b7cab6a49a503b" + integrity sha512-PJEqBwAleffCMETaVm/fUgHldzBE35JFk3/9LL6NUA5EXa3qednu+UT6M7E5iBu3zIQZCULYIiZ90fBYHt6xUw== + dependencies: + "@types/semver" "^7.5.5" + semver "^7.5.2" + +"@hutson/parse-repository-url@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-5.0.0.tgz#bf344cc75136039bc41bcf5d1ddbcb40405fca3b" + integrity sha512-e5+YUKENATs1JgYHMzTr2MW/NDcXGfYFAuOQU8gJgF/kEh4EqKgfGrfLI67bMD4tbhZVlkigz/9YYwWcbOFthg== + +"@types/normalize-package-data@^2.4.3": + version "2.4.4" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" + integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== + +"@types/semver@^7.5.5": + version "7.5.8" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" + integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== + +add-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" + integrity sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ== + +array-ify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" + integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== + +chevrotain-allstar@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz#b7412755f5d83cc139ab65810cdb00d8db40e6ca" + integrity sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw== + dependencies: + lodash-es "^4.17.21" + +chevrotain@11.0.3: + version "11.0.3" + resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-11.0.3.tgz#88ffc1fb4b5739c715807eaeedbbf200e202fc1b" + integrity sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw== + dependencies: + "@chevrotain/cst-dts-gen" "11.0.3" + "@chevrotain/gast" "11.0.3" + "@chevrotain/regexp-to-ast" "11.0.3" + "@chevrotain/types" "11.0.3" + "@chevrotain/utils" "11.0.3" + lodash-es "4.17.21" + +compare-func@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" + integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA== + dependencies: + array-ify "^1.0.0" + dot-prop "^5.1.0" + +conventional-changelog-angular@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-8.0.0.tgz#5701386850f0e0c2e630b43ee7821d322d87e7a6" + integrity sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA== + dependencies: + compare-func "^2.0.0" + +conventional-changelog-atom@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-atom/-/conventional-changelog-atom-5.0.0.tgz#f3e06e06244bd0aef2e5f09ed590933d948e809c" + integrity sha512-WfzCaAvSCFPkznnLgLnfacRAzjgqjLUjvf3MftfsJzQdDICqkOOpcMtdJF3wTerxSpv2IAAjX8doM3Vozqle3g== + +conventional-changelog-cli@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-cli/-/conventional-changelog-cli-5.0.0.tgz#feda8f20873347f73042a810db1c03377c39068d" + integrity sha512-9Y8fucJe18/6ef6ZlyIlT2YQUbczvoQZZuYmDLaGvcSBP+M6h+LAvf7ON7waRxKJemcCII8Yqu5/8HEfskTxJQ== + dependencies: + add-stream "^1.0.0" + conventional-changelog "^6.0.0" + meow "^13.0.0" + tempfile "^5.0.0" + +conventional-changelog-codemirror@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-codemirror/-/conventional-changelog-codemirror-5.0.0.tgz#994ced326cf358c5e549f5ac59bf3f8cdc09f783" + integrity sha512-8gsBDI5Y3vrKUCxN6Ue8xr6occZ5nsDEc4C7jO/EovFGozx8uttCAyfhRrvoUAWi2WMm3OmYs+0mPJU7kQdYWQ== + +conventional-changelog-conventionalcommits@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-8.0.0.tgz#3fa2857c878701e7f0329db5a1257cb218f166fe" + integrity sha512-eOvlTO6OcySPyyyk8pKz2dP4jjElYunj9hn9/s0OB+gapTO8zwS9UQWrZ1pmF2hFs3vw1xhonOLGcGjy/zgsuA== + dependencies: + compare-func "^2.0.0" + +conventional-changelog-core@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-8.0.0.tgz#5166eea9ef58a659fc97b065525f4499a0d3f311" + integrity sha512-EATUx5y9xewpEe10UEGNpbSHRC6cVZgO+hXQjofMqpy+gFIrcGvH3Fl6yk2VFKh7m+ffenup2N7SZJYpyD9evw== + dependencies: + "@hutson/parse-repository-url" "^5.0.0" + add-stream "^1.0.0" + conventional-changelog-writer "^8.0.0" + conventional-commits-parser "^6.0.0" + git-raw-commits "^5.0.0" + git-semver-tags "^8.0.0" + hosted-git-info "^7.0.0" + normalize-package-data "^6.0.0" + read-package-up "^11.0.0" + read-pkg "^9.0.0" + +conventional-changelog-ember@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-ember/-/conventional-changelog-ember-5.0.0.tgz#cca926a68aa9bc2a6370b211906b1dea82564567" + integrity sha512-RPflVfm5s4cSO33GH/Ey26oxhiC67akcxSKL8CLRT3kQX2W3dbE19sSOM56iFqUJYEwv9mD9r6k79weWe1urfg== + +conventional-changelog-eslint@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-eslint/-/conventional-changelog-eslint-6.0.0.tgz#9d37abcf6ade84031ce01093be7447f2cd73098b" + integrity sha512-eiUyULWjzq+ybPjXwU6NNRflApDWlPEQEHvI8UAItYW/h22RKkMnOAtfCZxMmrcMO1OKUWtcf2MxKYMWe9zJuw== + +conventional-changelog-express@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-express/-/conventional-changelog-express-5.0.0.tgz#e08fb0f2c27bc5319ce7d8e78c9e9fb99ae1feb5" + integrity sha512-D8Q6WctPkQpvr2HNCCmwU5GkX22BVHM0r4EW8vN0230TSyS/d6VQJDAxGb84lbg0dFjpO22MwmsikKL++Oo/oQ== + +conventional-changelog-jquery@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-jquery/-/conventional-changelog-jquery-6.0.0.tgz#5b6bd8b4a720363dc6c2162a3f751961c55256b0" + integrity sha512-2kxmVakyehgyrho2ZHBi90v4AHswkGzHuTaoH40bmeNqUt20yEkDOSpw8HlPBfvEQBwGtbE+5HpRwzj6ac2UfA== + +conventional-changelog-jshint@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-jshint/-/conventional-changelog-jshint-5.0.0.tgz#42bcc629b9c75bb118364754d120ae49fd742b85" + integrity sha512-gGNphSb/opc76n2eWaO6ma4/Wqu3tpa2w7i9WYqI6Cs2fncDSI2/ihOfMvXveeTTeld0oFvwMVNV+IYQIk3F3g== + dependencies: + compare-func "^2.0.0" + +conventional-changelog-preset-loader@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-5.0.0.tgz#922ad617c13ad3243bef967cfc0f8373893c216d" + integrity sha512-SetDSntXLk8Jh1NOAl1Gu5uLiCNSYenB5tm0YVeZKePRIgDW9lQImromTwLa3c/Gae298tsgOM+/CYT9XAl0NA== + +conventional-changelog-writer@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-8.0.0.tgz#81522ed40400a4ca8ab78a42794aae9667c745ae" + integrity sha512-TQcoYGRatlAnT2qEWDON/XSfnVG38JzA7E0wcGScu7RElQBkg9WWgZd1peCWFcWDh1xfb2CfsrcvOn1bbSzztA== + dependencies: + "@types/semver" "^7.5.5" + conventional-commits-filter "^5.0.0" + handlebars "^4.7.7" + meow "^13.0.0" + semver "^7.5.2" + +conventional-changelog@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog/-/conventional-changelog-6.0.0.tgz#ef941d2fde727be20e0f3a342e4e3b235d6e8663" + integrity sha512-tuUH8H/19VjtD9Ig7l6TQRh+Z0Yt0NZ6w/cCkkyzUbGQTnUEmKfGtkC9gGfVgCfOL1Rzno5NgNF4KY8vR+Jo3w== + dependencies: + conventional-changelog-angular "^8.0.0" + conventional-changelog-atom "^5.0.0" + conventional-changelog-codemirror "^5.0.0" + conventional-changelog-conventionalcommits "^8.0.0" + conventional-changelog-core "^8.0.0" + conventional-changelog-ember "^5.0.0" + conventional-changelog-eslint "^6.0.0" + conventional-changelog-express "^5.0.0" + conventional-changelog-jquery "^6.0.0" + conventional-changelog-jshint "^5.0.0" + conventional-changelog-preset-loader "^5.0.0" + +conventional-commits-filter@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz#72811f95d379e79d2d39d5c0c53c9351ef284e86" + integrity sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q== + +conventional-commits-parser@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-6.0.0.tgz#74e3be5344d8cd99f7c3353da2efa1d1dd618061" + integrity sha512-TbsINLp48XeMXR8EvGjTnKGsZqBemisPoyWESlpRyR8lif0lcwzqz+NMtYSj1ooF/WYjSuu7wX0CtdeeMEQAmA== + dependencies: + meow "^13.0.0" + +dot-prop@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + +find-up-simple@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-up-simple/-/find-up-simple-1.0.0.tgz#21d035fde9fdbd56c8f4d2f63f32fd93a1cfc368" + integrity sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw== + +git-raw-commits@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-5.0.0.tgz#38af4301e70c17be03fec01a37a6cd90ce0db04e" + integrity sha512-I2ZXrXeOc0KrCvC7swqtIFXFN+rbjnC7b2T943tvemIOVNl+XP8YnA9UVwqFhzzLClnSA60KR/qEjLpXzs73Qg== + dependencies: + "@conventional-changelog/git-client" "^1.0.0" + meow "^13.0.0" + +git-semver-tags@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-8.0.0.tgz#745ee2d934f74c70014d0ed617e18f4712950e32" + integrity sha512-N7YRIklvPH3wYWAR2vysaqGLPRcpwQ0GKdlqTiVN5w1UmCdaeY3K8s6DMKRCh54DDdzyt/OAB6C8jgVtb7Y2Fg== + dependencies: + "@conventional-changelog/git-client" "^1.0.0" + meow "^13.0.0" + +handlebars@^4.7.7: + version "4.7.8" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" + integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.2" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + +hosted-git-info@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.2.tgz#9b751acac097757667f30114607ef7b661ff4f17" + integrity sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w== + dependencies: + lru-cache "^10.0.1" + +index-to-position@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/index-to-position/-/index-to-position-0.1.2.tgz#e11bfe995ca4d8eddb1ec43274488f3c201a7f09" + integrity sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g== + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +java-parser@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/java-parser/-/java-parser-2.3.2.tgz#9a930dfb397a9ada0bb1e8a18a9086eb65f2adf8" + integrity sha512-/O42UbEHy3VVJw8W0ruHkQjW75oWvQx4QisoUDRIGir6q3/IZ4JslDMPMYEqp7LU56PYJkH5uXdQiBaCXt/Opw== + dependencies: + chevrotain "11.0.3" + chevrotain-allstar "0.3.1" + lodash "4.17.21" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +lodash-es@4.17.21, lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + +lodash@4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +lru-cache@^10.0.1: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +meow@^13.0.0: + version "13.2.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-13.2.0.tgz#6b7d63f913f984063b3cc261b6e8800c4cd3474f" + integrity sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA== + +minimist@^1.2.5: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +normalize-package-data@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-6.0.2.tgz#a7bc22167fe24025412bcff0a9651eb768b03506" + integrity sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g== + dependencies: + hosted-git-info "^7.0.0" + semver "^7.3.5" + validate-npm-package-license "^3.0.4" + +parse-json@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-8.1.0.tgz#91cdc7728004e955af9cb734de5684733b24a717" + integrity sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA== + dependencies: + "@babel/code-frame" "^7.22.13" + index-to-position "^0.1.2" + type-fest "^4.7.1" + +picocolors@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +prettier-plugin-java@^2.5.0: + version "2.6.5" + resolved "https://registry.yarnpkg.com/prettier-plugin-java/-/prettier-plugin-java-2.6.5.tgz#b8c1ab70fc118675eb69b90212e34a5bc86c22aa" + integrity sha512-2RkPNXyYpP5dRhr04pz45n+e5LXwYWTh1JXrztiCkZTGGokIGYrfwUuGa8csnDoGbP6CDPgVm8zZSIm/9I0SRQ== + dependencies: + java-parser "2.3.2" + lodash "4.17.21" + prettier "3.2.5" + +prettier@3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" + integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== + +prettier@^3.2.5: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== + +read-package-up@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/read-package-up/-/read-package-up-11.0.0.tgz#71fb879fdaac0e16891e6e666df22de24a48d5ba" + integrity sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ== + dependencies: + find-up-simple "^1.0.0" + read-pkg "^9.0.0" + type-fest "^4.6.0" + +read-pkg@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-9.0.1.tgz#b1b81fb15104f5dbb121b6bbdee9bbc9739f569b" + integrity sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA== + dependencies: + "@types/normalize-package-data" "^2.4.3" + normalize-package-data "^6.0.0" + parse-json "^8.0.0" + type-fest "^4.6.0" + unicorn-magic "^0.1.0" + +semver@^7.3.5, semver@^7.5.2: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spdx-correct@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" + integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.20" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz#e44ed19ed318dd1e5888f93325cee800f0f51b89" + integrity sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw== + +temp-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-3.0.0.tgz#7f147b42ee41234cc6ba3138cd8e8aa2302acffa" + integrity sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw== + +tempfile@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/tempfile/-/tempfile-5.0.0.tgz#40c141e441709fe2d9c17c138e81d4c33fbc9e03" + integrity sha512-bX655WZI/F7EoTDw9JvQURqAXiPHi8o8+yFxPF2lWYyz1aHnmMRuXWqL6YB6GmeO0o4DIYWHLgGNi/X64T+X4Q== + dependencies: + temp-dir "^3.0.0" + +type-fest@^4.6.0, type-fest@^4.7.1: + version "4.26.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.26.1.tgz#a4a17fa314f976dd3e6d6675ef6c775c16d7955e" + integrity sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg== + +uglify-js@^3.1.4: + version "3.19.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== + +unicorn-magic@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4" + integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ== + +validate-npm-package-license@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==