diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..a22ded5 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,42 @@ +{ + "name": "Java 17 and maven 3.8.8 DevContainer to build Java RAG example with Azure AI", + "image": "mcr.microsoft.com/devcontainers/java:1-17-bullseye", + "features": { + "azure-cli": "latest", + "ghcr.io/azure/azure-dev/azd:latest": { + "version": "1.7.0" + }, + "ghcr.io/devcontainers/features/java:1": { + "version": "none", + "installMaven": true, + "mavenVersion": "3.8.8" + }, + "ghcr.io/devcontainers/features/node:1": { + "version": "20.5.0" + }, + + "ghcr.io/devcontainers/features/git:1": { + "version": "2.39.1" + }, + "ghcr.io/devcontainers-contrib/features/typescript:2": {}, + "ghcr.io/devcontainers/features/kubectl-helm-minikube:1": { + "version": "1.1.8" + }, + "docker-in-docker": { + "version": "latest", + "moby": true, + "dockerDashComposeVersion": "v1" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.vscode-github-actions", + "ms-azuretools.azure-dev", + "ms-azuretools.vscode-bicep", + "vscjava.vscode-java-pack", + "amodio.tsl-problem-matcher" + ] + } + } +} \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..526c8a3 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.sh text eol=lf \ No newline at end of file diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..c72a574 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,9 @@ +# Microsoft Open Source Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). + +Resources: + +- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) +- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) +- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..09f1145 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,36 @@ + +> Please provide us with the following information: +> --------------------------------------------------------------- + +### This issue is for a: (mark with an `x`) +``` +- [ ] bug report -> please search issues before submitting +- [ ] feature request +- [ ] documentation issue or request +- [ ] regression (a behavior that used to work and stopped in a new release) +``` + +### Minimal steps to reproduce +> + +### Any log messages given by the failure +> + +### Expected/desired behavior +> + +### OS and Version? +> Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?) + +### azd version? +> run `azd version` and copy paste here. + +### Versions +> + +### Mention any other details that might be useful + +> --------------------------------------------------------------- +> Thanks! We'll be in touch soon. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..12475f3 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,45 @@ +## Purpose + +* ... + +## Does this introduce a breaking change? + +``` +[ ] Yes +[ ] No +``` + +## Pull Request Type +What kind of change does this Pull Request introduce? + + +``` +[ ] Bugfix +[ ] Feature +[ ] Code style update (formatting, local variables) +[ ] Refactoring (no functional changes, no api changes) +[ ] Documentation content changes +[ ] Other... Please describe: +``` + +## How to Test +* Get the code + +``` +git clone [repo-address] +cd [repo-name] +git checkout [branch-name] +npm install +``` + +* Test the code + +``` +``` + +## What to Check +Verify that the following are valid +* ... + +## Other Information + \ No newline at end of file diff --git a/.github/workflows/app-ci.yaml b/.github/workflows/app-ci.yaml new file mode 100644 index 0000000..9f56928 --- /dev/null +++ b/.github/workflows/app-ci.yaml @@ -0,0 +1,100 @@ +name: APP CI/CD Pipeline + +on: + push: + branches: + - main + paths: + - "app/**" + tags: + - v*.*.* + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + outputs: + env-name: ${{steps.set-deploy-env.outputs.DEPLOY_ENVIRONMENT}} + steps: + - uses: actions/checkout@v2 + + - name: Set up Java version + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '17' + cache: 'maven' + + - name: Set environment for branch + id: set-deploy-env + run: | + echo "checking branch name [${{github.ref_name}}]" + if [[ ${{github.ref_name}} == 'main' ]]; then + echo "main branch detected. Set Development environment" + echo "DEPLOY_ENVIRONMENT=Development" >> "$GITHUB_OUTPUT" + elif [[ ${{github.ref_name}} == *'release'* ]]; then + echo "release branch detected. Set Test environment" + echo "DEPLOY_ENVIRONMENT=Test" >> "$GITHUB_OUTPUT" + elif [[ ${{github.ref_name}} == *'v'* ]]; then + echo "tag detected. Set Production environment" + echo "DEPLOY_ENVIRONMENT=Production" >> "$GITHUB_OUTPUT" + else + echo "branch not detected. Set Development environment as default" + echo "DEPLOY_ENVIRONMENT=Development" >> "$GITHUB_OUTPUT" + fi + - name: Build React Frontend + run: | + echo "Building frontend and merge into spring boot static folder. Environment [${{ steps.set-deploy-env.outputs.DEPLOY_ENVIRONMENT }}]" + cd ./app/frontend + npm install + npm run build + mkdir -p ../backend/src/main/resources/static + cp -r ./build/* ../backend/src/main/resources/static + + - name: Verify Indexer project + run: | + echo "Testing indexer project." + cd ./app/indexer + mvn test + + - name: Build Spring Boot App + run: | + echo "Building spring boot app. Environment [${{ steps.set-deploy-env.outputs.DEPLOY_ENVIRONMENT }}]" + cd ./app/backend + mvn package + artifactid=$(mvn help:evaluate -Dexpression=project.artifactId -q -DforceStdout) + jarversion=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + originaljarname="$artifactid-$jarversion.jar" + echo "Renaming $originaljarname to app.jar" + # Renaming jar so it is auto detected by app service + mv ./target/$originaljarname ./target/app.jar + + - name: Upload artifacts for backend deployment jobs + uses: actions/upload-artifact@v2 + with: + name: spring-boot-app + path: | + ./app/backend/target/app.jar + + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: ${{ needs.build.outputs.env-name}} + url: ${{ steps.deploy-app.outputs.webapp-url }} + + steps: + - name: Download backend artifact from build job + uses: actions/download-artifact@v2 + with: + name: spring-boot-app + path: ./backend + + - name: 'Deploy backend to Azure Web App' + uses: azure/webapps-deploy@v2 + id: deploy-app + with: + app-name: ${{ vars.AZUREAPPSERVICE_APP_NAME }} + package: ./backend + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE}} diff --git a/.github/workflows/infra-ci.yaml b/.github/workflows/infra-ci.yaml new file mode 100644 index 0000000..68311c4 --- /dev/null +++ b/.github/workflows/infra-ci.yaml @@ -0,0 +1,143 @@ +name: Infra CI Pipeline + +on: + push: + branches: + - main + paths: + - "deploy/**" + + workflow_dispatch: + +# To configure required secrets for connecting to Azure, simply run `azd pipeline config` + +# Set up permissions for deploying with secretless Azure federated credentials +# https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-portal%2Clinux#set-up-azure-login-with-openid-connect-authentication +permissions: + id-token: write + contents: read + security-events: write + +jobs: + validate-bicep: + name: "Infra Biceps Validation" + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Filter Changes + uses: dorny/paths-filter@v2 + id: changes + with: + filters: | + app-service: + - 'deploy/app-service/**' + aks: + - 'deploy/aks/**' + aca: + - 'deploy/aca/**' + - name: Build App Service Bicep for linting + if: steps.changes.outputs.app-service == 'true' + uses: azure/CLI@v1 + with: + inlineScript: az config set bicep.use_binary_from_path=false && az bicep build -f deploy/app-service/infra/main.bicep --stdout + + - name: Build AKS Bicep for linting + if: steps.changes.outputs.aks == 'true' + uses: azure/CLI@v1 + with: + inlineScript: az config set bicep.use_binary_from_path=false && az bicep build -f deploy/aks/infra/main.bicep --stdout + + - name: Build ACA Bicep for linting + if: steps.changes.outputs.aca == 'true' + uses: azure/CLI@v1 + with: + inlineScript: az config set bicep.use_binary_from_path=false && az bicep build -f deploy/aca/infra/main.bicep --stdout + + - name: Run Microsoft Security DevOps Analysis + uses: microsoft/security-devops-action@v1 + id: msdo + continue-on-error: true + with: + tools: templateanalyzer + + - name: Upload alerts to Security tab + uses: github/codeql-action/upload-sarif@v2 + if: github.repository == 'Azure-Samples/azure-search-openai-demo-java' + with: + sarif_file: ${{ steps.msdo.outputs.sarifFile }} + + +# deploy: +# name: "Deploy Infra and App using azd" +# runs-on: ubuntu-latest +# environment: +# name: "Development" +# env: +# AZURE_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }} +# AZURE_TENANT_ID: ${{ vars.AZURE_TENANT_ID }} +# AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }} +# AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} +# steps: +# - name: Checkout +# uses: actions/checkout@v4 + +# - name: Install azd +# uses: Azure/setup-azd@v0.1.0 + +# - name: Log in with Azure (Federated Credentials) +# if: ${{ env.AZURE_CLIENT_ID != '' }} +# run: | +# azd auth login ` +# --client-id "$Env:AZURE_CLIENT_ID" ` +# --federated-credential-provider "github" ` +# --tenant-id "$Env:AZURE_TENANT_ID" +# shell: pwsh + +# - name: Log in with Azure (Client Credentials) +# if: ${{ env.AZURE_CREDENTIALS != '' }} +# run: | +# $info = $Env:AZURE_CREDENTIALS | ConvertFrom-Json -AsHashtable; +# Write-Host "::add-mask::$($info.clientSecret)" + +# azd auth login ` +# --client-id "$($info.clientId)" ` +# --client-secret "$($info.clientSecret)" ` +# --tenant-id "$($info.tenantId)" +# shell: pwsh +# env: +# AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + +# - name: Provision Infrastructure +# run: azd provision --no-prompt +# env: +# AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }} +# AZURE_LOCATION: ${{ vars.AZURE_LOCATION }} +# AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }} +# AZURE_FORMRECOGNIZER_RESOURCE_GROUP: ${{ vars.AZURE_FORMRECOGNIZER_RESOURCE_GROUP }} +# AZURE_FORMRECOGNIZER_SERVICE: ${{ vars.AZURE_FORMRECOGNIZER_RESOURCE_GROUP }} +# AZURE_OPENAI_RESOURCE_GROUP: ${{ vars.AZURE_FORMRECOGNIZER_SERVICE }} +# AZURE_OPENAI_SERVICE: ${{ vars.AZURE_OPENAI_SERVICE }} +# AZURE_RESOURCE_GROUP: ${{ vars.AZURE_RESOURCE_GROUP }} +# AZURE_SEARCH_SERVICE: ${{ vars.AZURE_SEARCH_SERVICE }} +# AZURE_SEARCH_SERVICE_RESOURCE_GROUP: ${{ vars.AZURE_SEARCH_SERVICE_RESOURCE_GROUP }} +# AZURE_STORAGE_ACCOUNT: ${{ vars.AZURE_STORAGE_ACCOUNT }} +# AZURE_STORAGE_RESOURCE_GROUP: ${{ vars.AZURE_STORAGE_RESOURCE_GROUP }} + +# - name: Deploy Application +# run: azd deploy --no-prompt +# env: +# AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }} +# AZURE_LOCATION: ${{ vars.AZURE_LOCATION }} +# AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }} +# AZURE_FORMRECOGNIZER_RESOURCE_GROUP: ${{ vars.AZURE_FORMRECOGNIZER_RESOURCE_GROUP }} +# AZURE_FORMRECOGNIZER_SERVICE: ${{ vars.AZURE_FORMRECOGNIZER_RESOURCE_GROUP }} +# AZURE_OPENAI_RESOURCE_GROUP: ${{ vars.AZURE_FORMRECOGNIZER_SERVICE }} +# AZURE_OPENAI_SERVICE: ${{ vars.AZURE_OPENAI_SERVICE }} +# AZURE_RESOURCE_GROUP: ${{ vars.AZURE_RESOURCE_GROUP }} +# AZURE_SEARCH_SERVICE: ${{ vars.AZURE_SEARCH_SERVICE }} +# AZURE_SEARCH_SERVICE_RESOURCE_GROUP: ${{ vars.AZURE_SEARCH_SERVICE_RESOURCE_GROUP }} +# AZURE_STORAGE_ACCOUNT: ${{ vars.AZURE_STORAGE_ACCOUNT }} +# AZURE_STORAGE_RESOURCE_GROUP: ${{ vars.AZURE_STORAGE_RESOURCE_GROUP }} + + diff --git a/.github/workflows/nightly-jobs.yaml b/.github/workflows/nightly-jobs.yaml new file mode 100644 index 0000000..9350a1f --- /dev/null +++ b/.github/workflows/nightly-jobs.yaml @@ -0,0 +1,104 @@ +name: Nightly and CICD Jobs + +on: + pull_request: + branches: [ main ] + schedule: + - cron: '0 0 * * *' # Run at midnight every day + workflow_dispatch: + +permissions: + id-token: write + contents: read + security-events: write + +jobs: + validate-bicep: + name: "Infra Biceps Validation" + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Filter Changes + uses: dorny/paths-filter@v2 + id: changes + with: + filters: | + app-service: + - 'deploy/app-service/**' + aks: + - 'deploy/aks/**' + aca: + - 'deploy/aca/**' + - name: Build App Service Bicep for linting + if: steps.changes.outputs.app-service == 'true' + uses: azure/CLI@v1 + with: + inlineScript: az config set bicep.use_binary_from_path=false && az bicep build -f deploy/app-service/infra/main.bicep --stdout + + - name: Build AKS Bicep for linting + if: steps.changes.outputs.aks == 'true' + uses: azure/CLI@v1 + with: + inlineScript: az config set bicep.use_binary_from_path=false && az bicep build -f deploy/aks/infra/main.bicep --stdout + + - name: Build ACA Bicep for linting + if: steps.changes.outputs.aca == 'true' + uses: azure/CLI@v1 + with: + inlineScript: az config set bicep.use_binary_from_path=false && az bicep build -f deploy/aca/infra/main.bicep --stdout + + - name: Run Microsoft Security DevOps Analysis + uses: microsoft/security-devops-action@v1 + id: msdo + continue-on-error: true + with: + tools: templateanalyzer + + - name: Upload alerts to Security tab + uses: github/codeql-action/upload-sarif@v2 + if: github.repository == 'Azure-Samples/azure-search-openai-demo-java' + with: + sarif_file: ${{ steps.msdo.outputs.sarifFile }} + + frontend: + name: "Front-end validation" + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Build React Frontend + run: | + echo "Building front-end and merge into Spring Boot static folder." + cd ./app/frontend + npm install + npm run build + mkdir -p ../backend/src/main/resources/static + cp -r ./build/* ../backend/src/main/resources/static + + backend: + name: "Backend validation" + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Java version + uses: actions/setup-java@v2 + with: + distribution: 'microsoft' + java-version: '17' + cache: 'maven' + + - name: Verify Indexer project + run: | + echo "Testing indexer project." + cd ./app/indexer + mvn test + + - name: Build Spring Boot App + run: | + echo "Building Spring Boot app." + cd ./app/backend + mvn verify diff --git a/.github/workflows/stale-bot.yml b/.github/workflows/stale-bot.yml new file mode 100644 index 0000000..44dc9ab --- /dev/null +++ b/.github/workflows/stale-bot.yml @@ -0,0 +1,19 @@ +name: 'Close stale issues and PRs' +on: + schedule: + - cron: '30 1 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v8 + with: + stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this issue will be closed.' + stale-pr-message: 'This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed.' + close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' + close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.' + days-before-issue-stale: 60 + days-before-pr-stale: 60 + days-before-issue-close: -1 + days-before-pr-close: -1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7d5428a --- /dev/null +++ b/.gitignore @@ -0,0 +1,156 @@ +# Azure az webapp deployment details +.azure +*_env + +# Java IDE +.idea +*.iml + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# NPM +npm-debug.log* +node_modules +static/ + +# Generated manifests +app/backend/manifests/azd-env-configmap.yml +deploy/aks/easyauth/config-output.md +deploy/aks/easyauth/easyauth-ingress.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9f92a3d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +## [project-title] Changelog + + +# x.y.z (yyyy-mm-dd) + +*Features* +* ... + +*Bug Fixes* +* ... + +*Breaking Changes* +* ... diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..1617c3a --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,7 @@ +# These owners will be the default owners for everything in +# this repo. Unless a later match takes precedence, +# @global-owner1 and @global-owner2 will be requested for +# review when someone opens a pull request. +* @dantelmomsft +* @johnoliver +* @brunoborges diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a145f12 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,76 @@ +# Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. + +When you submit a pull request, a CLA bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + + - [Code of Conduct](#coc) + - [Issues and Bugs](#issue) + - [Feature Requests](#feature) + - [Submission Guidelines](#submit) + +## Code of Conduct +Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](https://opensource.microsoft.com/codeofconduct/). + +## Found an Issue? +If you find a bug in the source code or a mistake in the documentation, you can help us by +[submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can +[submit a Pull Request](#submit-pr) with a fix. + +## Want a Feature? +You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub +Repository. If you would like to *implement* a new feature, please submit an issue with +a proposal for your work first, to be sure that we can use it. + +* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr). + +## Submission Guidelines + +### Submitting an Issue +Before you submit an issue, search the archive, maybe your question was already answered. + +If your issue appears to be a bug, and hasn't been reported, open a new issue. +Help us to maximize the effort we can spend fixing issues and adding new +features, by not reporting duplicate issues. Providing the following information will increase the +chances of your issue being dealt with quickly: + +* **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps +* **Version** - what version is affected (e.g. 0.1.2) +* **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you +* **Browsers and Operating System** - is this a problem with all browsers? +* **Reproduce the Error** - provide a live example or an unambiguous set of steps +* **Related Issues** - has a similar issue been reported before? +* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be + causing the problem (line of code or commit) + +You can file new issues by providing the above information at the corresponding repository's issues link: https://github.com/Azure-Samples/azure-search-openai-demo-java/issues/new. + +### Submitting a Pull Request (PR) +Before you submit your Pull Request (PR) consider the following guidelines: + +* Search the repository (https://github.com/Azure-Samples/azure-search-openai-demo-java/pulls) for an open or closed PR + that relates to your submission. You don't want to duplicate effort. + +* Make your changes in a new git fork: + +* Commit your changes using a descriptive commit message +* Push your fork to GitHub: +* In GitHub, create a pull request +* If we suggest changes then: + * Make the required updates. + * Rebase your fork and force push to your GitHub repository (this will update your Pull Request): + + ```shell + git rebase master -i + git push -f + ``` + +That's it! Thank you for your contribution! diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..65f32d0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Azure Samples + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..db553e8 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ed74f7 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Personal Finance Assistant with Azure OpenAI - Java diff --git a/app/backend/.mvn/jvm.config b/app/backend/.mvn/jvm.config new file mode 100644 index 0000000..14a0c1a --- /dev/null +++ b/app/backend/.mvn/jvm.config @@ -0,0 +1,4 @@ +--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED +--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED diff --git a/app/backend/.mvn/wrapper/maven-wrapper.jar b/app/backend/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000..968b23b Binary files /dev/null and b/app/backend/.mvn/wrapper/maven-wrapper.jar differ diff --git a/app/backend/.mvn/wrapper/maven-wrapper.properties b/app/backend/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..0b3b65e --- /dev/null +++ b/app/backend/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.tar.gz diff --git a/app/backend/Dockerfile b/app/backend/Dockerfile new file mode 100644 index 0000000..45171c1 --- /dev/null +++ b/app/backend/Dockerfile @@ -0,0 +1,30 @@ +FROM mcr.microsoft.com/openjdk/jdk:17-mariner AS build + +WORKDIR /workspace/app +EXPOSE 3100 + +COPY mvnw . +COPY .mvn .mvn +COPY pom.xml . +COPY src src + +RUN chmod +x ./mvnw +# Convert CRLF to LF +RUN sed -i 's/\r$//' ./mvnw +RUN ./mvnw package -DskipTests +RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) + +FROM mcr.microsoft.com/openjdk/jdk:17-mariner + +ARG DEPENDENCY=/workspace/app/target/dependency +COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib +COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF +COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app + + +RUN curl -LJ -o /app/applicationinsights-agent-3.4.19.jar https://github.com/microsoft/ApplicationInsights-Java/releases/download/3.4.19/applicationinsights-agent-3.4.19.jar +COPY applicationinsights.json /app + +EXPOSE 8080 + +ENTRYPOINT ["java","-javaagent:/app/applicationinsights-agent-3.4.19.jar","-noverify", "-XX:MaxRAMPercentage=70", "-XX:+UseParallelGC", "-XX:ActiveProcessorCount=2", "-cp","app:app/lib/*","com.microsoft.openai.samples.assistant.Application"] \ No newline at end of file diff --git a/app/backend/applicationinsights.json b/app/backend/applicationinsights.json new file mode 100644 index 0000000..6611add --- /dev/null +++ b/app/backend/applicationinsights.json @@ -0,0 +1,5 @@ +{ + "role": { + "name": "api" + } + } \ No newline at end of file diff --git a/app/backend/manifest.yml b/app/backend/manifest.yml new file mode 100644 index 0000000..f48c3b0 --- /dev/null +++ b/app/backend/manifest.yml @@ -0,0 +1,11 @@ +--- +applications: +- name: rest-service-guides + memory: 256M + instances: 1 + random-route: true + domain: cfapps.io + timeout: 180 + buildpack: java_buildpack +# For Maven target/gs-rest-service-cors-0.1.0.jar + path: build/libs/gs-rest-service-cors-0.1.0.jar diff --git a/app/backend/manifests/backend-deployment.tmpl.yml b/app/backend/manifests/backend-deployment.tmpl.yml new file mode 100644 index 0000000..f7f48a3 --- /dev/null +++ b/app/backend/manifests/backend-deployment.tmpl.yml @@ -0,0 +1,29 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: backend-deployment + namespace: azure-open-ai + labels: + app: backend +spec: + replicas: 1 + selector: + matchLabels: + app: backend + template: + metadata: + labels: + app: backend + spec: + containers: + - name: backend + image: {{.Env.SERVICE_API_IMAGE_NAME}} + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + envFrom: + - configMapRef: + name: azd-env-configmap + resources: + requests: + memory: "2Gi" diff --git a/app/backend/manifests/backend-service.yml b/app/backend/manifests/backend-service.yml new file mode 100644 index 0000000..85b4eb6 --- /dev/null +++ b/app/backend/manifests/backend-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: backend-service + namespace: azure-open-ai +spec: + type: ClusterIP + ports: + - protocol: TCP + port: 80 + targetPort: 8080 + selector: + app: backend diff --git a/app/backend/manifests/ingress.yml b/app/backend/manifests/ingress.yml new file mode 100644 index 0000000..be8985b --- /dev/null +++ b/app/backend/manifests/ingress.yml @@ -0,0 +1,27 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-api + namespace: azure-open-ai +# annotations: +# nginx.ingress.kubernetes.io/use-regex: "true" +# nginx.ingress.kubernetes.io/rewrite-target: /$2 +spec: + ingressClassName: webapprouting.kubernetes.azure.com + rules: + - http: + paths: + - path: /api + pathType: Prefix + backend: + service: + name: backend-service + port: + number: 80 + - path: / + pathType: Prefix + backend: + service: + name: frontend-service + port: + number: 80 \ No newline at end of file diff --git a/app/backend/mvnw b/app/backend/mvnw new file mode 100644 index 0000000..eb65ff2 --- /dev/null +++ b/app/backend/mvnw @@ -0,0 +1,305 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ "$MVNW_REPOURL" = true]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/app/backend/mvnw.cmd b/app/backend/mvnw.cmd new file mode 100644 index 0000000..4f5150a --- /dev/null +++ b/app/backend/mvnw.cmd @@ -0,0 +1,172 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar" + ) + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/app/backend/pom.xml b/app/backend/pom.xml new file mode 100644 index 0000000..6c82c3e --- /dev/null +++ b/app/backend/pom.xml @@ -0,0 +1,251 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.13 + + + com.microsoft.openai.samples.assistant + personal-finance-assistant-java + 1.0.0-SNAPSHOT + personal-finance-assistant-java + This sample demonstrate how to create a generative ai multi-agent solution for a banking personal assistant + + 17 + + 4.9.0 + 11.6.0-beta.8 + 1.0.1 + 4.5.1 + 3.11.0 + + 2.40.0 + 1.18.1 + 0.10.14 + 2.22.0 + 4.7.3.6 + + + + + + com.azure.spring + spring-cloud-azure-dependencies + ${spring-cloud-azure.version} + pom + import + + + com.microsoft.semantic-kernel + semantickernel-bom + ${semantic-kernel.version} + import + pom + + + + + org.apache.commons + commons-lang3 + 3.13.0 + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + com.fasterxml.jackson.core + jackson-databind + compile + + + com.fasterxml.jackson.core + jackson-core + compile + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.mockito + mockito-inline + ${mockito-inline.version} + test + + + + com.azure + azure-identity + 1.11.2 + + + com.azure + azure-core + 1.45.1 + + + + com.azure + azure-ai-documentintelligence + 1.0.0-beta.2 + + + org.json + json + 20240303 + + + + + com.azure + azure-search-documents + ${azure-search.version} + + + com.azure + azure-core-serializer-json-jackson + + + + + + com.azure + azure-storage-blob + + + + + com.microsoft.semantic-kernel + semantickernel-api + + + com.microsoft.semantic-kernel + semantickernel-aiservices-openai + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + bug-check + + false + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler-plugin.version} + + ${java.version} + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + true + + -XDcompilePolicy=simple + -Xplugin:ErrorProne + -XepOpt:NullAway:AnnotatedPackages=com.microsoft.openai.samples.rag + -Xep:AlmostJavadoc:OFF -Xep:MissingSummary:OFF + -Xep:UnusedVariable:OFF -Xep:EmptyBlockTag:OFF + + + + + com.google.errorprone + error_prone_core + ${google.errorprone.core.version} + + + com.uber.nullaway + nullaway + ${com.uber.nullaway.version} + + + + + + com.diffplug.spotless + spotless-maven-plugin + ${maven.spotless-plugin.version} + + + check + + check + + compile + + + apply + + apply + + process-sources + + + + + + ${google.java.format.version} + + true + + + // Copyright (c) Microsoft. All rights reserved. + + + + + + + com.github.spotbugs + spotbugs-maven-plugin + ${maven.spotbugs-plugin.version} + + spotbugs-exclude.xml + Max + + Normal + + + + + spotbugs + check + + + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + + + + + + + diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/Application.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/Application.java new file mode 100644 index 0000000..30b5ec7 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/Application.java @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + private static final Logger LOG = LoggerFactory.getLogger(Application.class); + + public static void main(String[] args) { + LOG.info( + "Application profile from system property is [{}]", + System.getProperty("spring.profiles.active")); + new SpringApplication(Application.class).run(args); + } +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/AgentContext.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/AgentContext.java new file mode 100644 index 0000000..27191c1 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/AgentContext.java @@ -0,0 +1,21 @@ +package com.microsoft.openai.samples.assistant.agent; +public class AgentContext { + + private String result; + + + public void AgentContext() { + } + + public void AgentContext(String result) { + this.result = result; + } + + public String getResult() { + return result; + } + public void setResult(String result) { + this.result = result; + } + +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/HistoryReportingAgent.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/HistoryReportingAgent.java new file mode 100644 index 0000000..0a62215 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/HistoryReportingAgent.java @@ -0,0 +1,165 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.agent; + +import com.azure.ai.openai.OpenAIAsyncClient; +import com.azure.ai.openai.OpenAIClientBuilder; +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLogOptions; +import com.microsoft.openai.samples.assistant.plugin.TransactionHistoryPlugin; +import com.microsoft.semantickernel.Kernel; +import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; +import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatMessageContent; +import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIFunctionToolCall; +import com.microsoft.semantickernel.contextvariables.CaseInsensitiveMap; +import com.microsoft.semantickernel.contextvariables.ContextVariable; +import com.microsoft.semantickernel.orchestration.FunctionResult; +import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; +import com.microsoft.semantickernel.orchestration.InvocationContext; +import com.microsoft.semantickernel.orchestration.ToolCallBehavior; +import com.microsoft.semantickernel.plugin.KernelPluginFactory; +import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; +import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; +import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.stream.Collectors; + +public class HistoryReportingAgent { + private static final Logger LOGGER = LoggerFactory.getLogger(HistoryReportingAgent.class); + private OpenAIAsyncClient client; + + private Kernel kernel; + + private ChatCompletionService chat; + + private String HISTORY_AGENT_SYSTEM_MESSAGE = """ + you are a personal financial advisor who help the user with their recurrent bill payments. To search about the payments history you need to know the payee name. + If the user doesn't provide the payee name, search the last 10 transactions order by date. + If the user want to search last transactions for a specific payee ask to provide the payee name. + """; + + public HistoryReportingAgent(OpenAIAsyncClient client, String modelId){ + this.client = client; + this.chat = OpenAIChatCompletion.builder() + .withModelId(modelId) + .withOpenAIAsyncClient(client) + .build(); + + var plugin = KernelPluginFactory.createFromObject(new TransactionHistoryPlugin(), "TransactionHistoryPlugin"); + + + kernel = Kernel.builder() + .withAIService(ChatCompletionService.class, chat) + .withPlugin(plugin) + .build(); + } + public HistoryReportingAgent(String azureClientKey, String clientEndpoint, String modelId){ + this.client = new OpenAIClientBuilder() + .credential(new AzureKeyCredential(azureClientKey)) + .endpoint(clientEndpoint) + .httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS)) + .buildAsyncClient(); + + this.chat = OpenAIChatCompletion.builder() + .withModelId(modelId) + .withOpenAIAsyncClient(client) + .build(); + + var plugin = KernelPluginFactory.createFromObject(new TransactionHistoryPlugin(), "TransactionHistoryPlugin"); + + + kernel = Kernel.builder() + .withAIService(ChatCompletionService.class, chat) + .withPlugin(plugin) + .build(); + } + + public AgentContext run (ChatHistory userChatHistory) { + LOGGER.info("======== HistoryAndTransaction Agent: Starting ========"); + + AgentContext agentContext = new AgentContext(); + + var agentChatHistory = new ChatHistory(HISTORY_AGENT_SYSTEM_MESSAGE); + userChatHistory.forEach( chatMessageContent -> { + if(chatMessageContent.getAuthorRole() != AuthorRole.SYSTEM) + agentChatHistory.addMessage(chatMessageContent); + }); + + + while (true) { + var messages = this.chat.getChatMessageContentsAsync( + agentChatHistory, + kernel, + InvocationContext.builder() + .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)).build()) + .block(); + + var message = messages.get(0); + agentContext.setResult(message.getContent()); + + + List toolCalls = messages.stream() + .filter(it -> it instanceof OpenAIChatMessageContent) + .map(it -> (OpenAIChatMessageContent) it) + .map(OpenAIChatMessageContent::getToolCall) + .flatMap(List::stream) + .collect(Collectors.toList()); + + if (toolCalls.isEmpty()) { + break; + } + + messages.stream() + .forEach(it -> agentChatHistory.addMessage(it)); + + for (var toolCall : toolCalls) { + + String content = null; + try { + // getFunction will throw an exception if the function is not found + var fn = kernel.getFunction(toolCall.getPluginName(), + toolCall.getFunctionName()); + FunctionResult fnResult = fn + .invokeAsync(kernel, toolCall.getArguments(), null, null).block(); + content = (String) fnResult.getResult(); + } catch (IllegalArgumentException e) { + content = "Unable to find function. Please try again!"; + } + + agentChatHistory.addMessage( + AuthorRole.TOOL, + content, + StandardCharsets.UTF_8, + new FunctionResultMetadata(new CaseInsensitiveMap<>() { + { + put(FunctionResultMetadata.ID, ContextVariable.of(toolCall.getId())); + } + })); + } + } + return agentContext; + } + + + + public static void main(String[] args) throws NoSuchMethodException { + + String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); + String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); + String MODEL_ID = System.getenv() + .getOrDefault("MODEL_ID", "gpt-3.5-turbo-1106"); + + HistoryReportingAgent agent = new HistoryReportingAgent(AZURE_CLIENT_KEY, CLIENT_ENDPOINT, MODEL_ID); + + agent.run(new ChatHistory()); + + + + } + } + + diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/IntentAgent.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/IntentAgent.java new file mode 100644 index 0000000..51c5e7b --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/IntentAgent.java @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.agent; + +import com.azure.ai.openai.OpenAIAsyncClient; +import com.azure.ai.openai.OpenAIClientBuilder; +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLogOptions; +import com.microsoft.semantickernel.Kernel; +import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; +import com.microsoft.semantickernel.orchestration.*; +import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; +import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; +import org.json.JSONObject; + +public class IntentAgent { + + private OpenAIAsyncClient client; + + private Kernel kernel; + + private ChatCompletionService chat; + + private String INTENT_SYSTEM_MESSAGE = """ + You are a personal financial advisor who help the user with their recurrent bill payments. + The user may want to pay the bill uploading a photo of the bill, or it may start the payment checking payments history for a specific payee. + In other cases it may want to just review the payments history. + Based on the conversation you need to identify the user intent and ask the user for the missing information. + The available intents are: + "BillPayment", "RepeatTransaction","TransactionHistory" + If none of the intents are identified provide the user with the list of the available intents. + + If an intent is identified return the output as json format as below + { + "intent": "BillPayment" + } + + If none of the intents are identified ask the user for more clarity and list of the available intents. Use always a json format as output + { + "intent": "None" + "clarify_sentence": "" + } + + Don't add any comments in the output or other characters, just the json format. + """; + + public IntentAgent(OpenAIAsyncClient client, String modelId){ + this.client = client; + this.chat = OpenAIChatCompletion.builder() + .withModelId(modelId) + .withOpenAIAsyncClient(client) + .build(); + + kernel = Kernel.builder() + .withAIService(ChatCompletionService.class, chat) + .build(); + } + public IntentAgent(String azureClientKey, String clientEndpoint, String modelId){ + this.client = new OpenAIClientBuilder() + .credential(new AzureKeyCredential(azureClientKey)) + .endpoint(clientEndpoint) + .httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS)) + .buildAsyncClient(); + + this.chat = OpenAIChatCompletion.builder() + .withModelId(modelId) + .withOpenAIAsyncClient(client) + .build(); + + kernel = Kernel.builder() + .withAIService(ChatCompletionService.class, chat) + .build(); + } + + public IntentResponse run(ChatHistory userChatHistory){ + var agentChatHistory = new ChatHistory(); + agentChatHistory.addAll(userChatHistory); + agentChatHistory.addSystemMessage(INTENT_SYSTEM_MESSAGE); + + + var messages = chat.getChatMessageContentsAsync( + agentChatHistory, + kernel, + InvocationContext.builder().withPromptExecutionSettings( + PromptExecutionSettings.builder() + .withTemperature(0.0) + .withTopP(1) + .withMaxTokens(200) + .build()) + .build()) + .block(); + + var message = messages.get(0); + + JSONObject json = new JSONObject(message.getContent()); + IntentType intentType = IntentType.valueOf(json.get("intent").toString()); + + return new IntentResponse(intentType,json); + } + + public static void main(String[] args) throws NoSuchMethodException { + + String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY"); + String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); + String MODEL_ID = System.getenv() + .getOrDefault("MODEL_ID", "gpt-3.5-turbo-1106"); + + IntentAgent agent = new IntentAgent(AZURE_CLIENT_KEY, CLIENT_ENDPOINT, MODEL_ID); + var chatHistory = new ChatHistory(); + // agent.run("when did I pay my last electricity bill?"); + //chatHistory.addUserMessage("when did I pay my last electricity bill?"); + chatHistory.addUserMessage("I want to pay my electricity bill"); + agent.run( chatHistory); + + } + } + + diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/IntentResponse.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/IntentResponse.java new file mode 100644 index 0000000..a478c8b --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/IntentResponse.java @@ -0,0 +1,27 @@ +package com.microsoft.openai.samples.assistant.agent; + + + +import org.json.JSONObject; + +public class IntentResponse { + + private IntentType intentType; + + private JSONObject jsonData; + + + + public IntentResponse(IntentType intentType, JSONObject jsonData) { + this.intentType = intentType; + this.jsonData = jsonData; + } + + public IntentType getIntentType() { + return intentType; + } + + public JSONObject getJsonData() { + return jsonData; + } +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/IntentType.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/IntentType.java new file mode 100644 index 0000000..9ecf129 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/IntentType.java @@ -0,0 +1,11 @@ +package com.microsoft.openai.samples.assistant.agent; + +public enum IntentType { + + BillPayment, + RepeatTransaction, + TransactionHistory, + None; + + +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/PaymentAgent.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/PaymentAgent.java new file mode 100644 index 0000000..21cf6cd --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/agent/PaymentAgent.java @@ -0,0 +1,158 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.agent; + +import com.azure.ai.documentintelligence.DocumentIntelligenceClient; +import com.azure.ai.openai.OpenAIAsyncClient; +import com.azure.ai.openai.OpenAIClientBuilder; +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLogOptions; +import com.microsoft.openai.samples.assistant.controller.ChatController; +import com.microsoft.openai.samples.assistant.invoice.DocumentIntelligenceInvoiceScanHelper; +import com.microsoft.openai.samples.assistant.plugin.InvoiceScanPlugin; +import com.microsoft.openai.samples.assistant.plugin.PaymentPlugin; +import com.microsoft.openai.samples.assistant.plugin.TransactionHistoryPlugin; +import com.microsoft.openai.samples.assistant.proxy.BlobStorageProxy; +import com.microsoft.semantickernel.Kernel; +import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion; +import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatMessageContent; +import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIFunctionToolCall; +import com.microsoft.semantickernel.contextvariables.CaseInsensitiveMap; +import com.microsoft.semantickernel.contextvariables.ContextVariable; +import com.microsoft.semantickernel.orchestration.FunctionResult; +import com.microsoft.semantickernel.orchestration.FunctionResultMetadata; +import com.microsoft.semantickernel.orchestration.InvocationContext; +import com.microsoft.semantickernel.orchestration.ToolCallBehavior; +import com.microsoft.semantickernel.plugin.KernelPluginFactory; +import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; +import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; +import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.stream.Collectors; + +public class PaymentAgent { + private static final Logger LOGGER = LoggerFactory.getLogger(PaymentAgent.class); + private OpenAIAsyncClient client; + + private Kernel kernel; + + private ChatCompletionService chat; + + private String PAYMENT_AGENT_SYSTEM_MESSAGE = """ + you are a personal financial advisor who help the user with their recurrent bill payments. The user may want to pay the bill uploading a photo of the bill, or it may start the payment checking transactions history for a specific payee. + For the bill payment you need to know the: bill id or invoice number, payee name, the total amount and the bill expiration date. + if you don't have enough information to pay the bill ask the user to provide the missing information. + you have the below functions available: + - paymentHistory: returns the list of the last payments based on the payee name + - payBill: it pays the bill based on the bill id or invoice number, payee name, total amount + - invoiceScan: it scans the invoice or bill photo to extract data + + Always check if the bill has been paid already based on payment history before asking to execute the bill payment. + Always ask for the payment method to use: direct debit, credit card, or bank transfer + Before executing the payBill function provide the user with the bill details and ask for confirmation. + If the payment succeeds provide the user with the payment confirmation. If not provide the user with the error message. + + """; + + public PaymentAgent(OpenAIAsyncClient client, String modelId, DocumentIntelligenceClient documentIntelligenceClient, BlobStorageProxy blobStorageProxy) { + this.client = client; + this.chat = OpenAIChatCompletion.builder() + .withModelId(modelId) + .withOpenAIAsyncClient(client) + .build(); + + kernel = Kernel.builder() + .withAIService(ChatCompletionService.class, chat) + .build(); + + var paymentPlugin = KernelPluginFactory.createFromObject(new PaymentPlugin(), "PaymentPlugin"); + var historyPlugin = KernelPluginFactory.createFromObject(new TransactionHistoryPlugin(), "TransactionHistoryPlugin"); + var invoiceScanPlugin = KernelPluginFactory.createFromObject(new InvoiceScanPlugin(new DocumentIntelligenceInvoiceScanHelper(documentIntelligenceClient,blobStorageProxy)), "InvoiceScanPlugin"); + + + kernel = Kernel.builder() + .withAIService(ChatCompletionService.class, chat) + .withPlugin(paymentPlugin) + .withPlugin(historyPlugin) + .withPlugin(invoiceScanPlugin) + .build(); + } + + + public AgentContext run (ChatHistory userChatHistory) { + LOGGER.info("======== Payment Agent: Starting ========"); + + AgentContext agentContext = new AgentContext(); + + var agentChatHistory = new ChatHistory(PAYMENT_AGENT_SYSTEM_MESSAGE); + + userChatHistory.forEach( chatMessageContent -> { + if(chatMessageContent.getAuthorRole() != AuthorRole.SYSTEM) + agentChatHistory.addMessage(chatMessageContent); + }); + + + + while (true) { + var messages = this.chat.getChatMessageContentsAsync( + agentChatHistory, + kernel, + InvocationContext.builder() + .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true)).build()) + .block(); + + var message = messages.get(0); + + agentContext.setResult(message.getContent()); + + + List toolCalls = messages.stream() + .filter(it -> it instanceof OpenAIChatMessageContent) + .map(it -> (OpenAIChatMessageContent) it) + .map(OpenAIChatMessageContent::getToolCall) + .flatMap(List::stream) + .collect(Collectors.toList()); + + if (toolCalls.isEmpty()) { + break; + } + + messages.stream() + .forEach(it -> agentChatHistory.addMessage(it)); + + for (var toolCall : toolCalls) { + + String content = null; + try { + // getFunction will throw an exception if the function is not found + var fn = kernel.getFunction(toolCall.getPluginName(), + toolCall.getFunctionName()); + FunctionResult fnResult = fn + .invokeAsync(kernel, toolCall.getArguments(), null, null).block(); + content = (String) fnResult.getResult(); + } catch (IllegalArgumentException e) { + content = "Unable to find function. Please try again!"; + } + + agentChatHistory.addMessage( + AuthorRole.TOOL, + content, + StandardCharsets.UTF_8, + new FunctionResultMetadata(new CaseInsensitiveMap<>() { + { + put(FunctionResultMetadata.ID, ContextVariable.of(toolCall.getId())); + } + })); + } + } + return agentContext; + } + + + } + + diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/common/ChatGPTConversation.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/common/ChatGPTConversation.java new file mode 100644 index 0000000..169d2c8 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/common/ChatGPTConversation.java @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.common; + +import com.azure.ai.openai.models.*; + +import java.util.List; + +public class ChatGPTConversation { + + private List messages; + private Integer tokenCount = 0; + + public ChatGPTConversation(List messages) { + this.messages = messages; + } + + public List toOpenAIChatMessages() { + return this.messages.stream() + .map( + message -> { + + ChatRole role = ChatRole.fromString( + message.role().toString()); + ChatRequestMessage chatMessage = null; + + if (role.equals(ChatRole.USER)) { + chatMessage = new ChatRequestUserMessage(message.content()); + } else if (role.equals(ChatRole.ASSISTANT)) { + chatMessage = new ChatRequestAssistantMessage(message.content()); + } else if (role.equals(ChatRole.SYSTEM)) { + chatMessage = new ChatRequestSystemMessage(message.content()); + } + return chatMessage; + }) + .toList(); + } + + public List getMessages() { + return messages; + } + + public void setMessages(List messages) { + this.messages = messages; + } +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/common/ChatGPTMessage.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/common/ChatGPTMessage.java new file mode 100644 index 0000000..a01f74c --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/common/ChatGPTMessage.java @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.common; + +import com.azure.core.util.ExpandableStringEnum; + +import java.util.Collection; + +public record ChatGPTMessage(ChatRole role, String content) { + + public static final class ChatRole extends ExpandableStringEnum { + public static final ChatRole SYSTEM = fromString("system"); + + public static final ChatRole ASSISTANT = fromString("assistant"); + + public static final ChatRole USER = fromString("user"); + + public static ChatRole fromString(String name) { + return fromString(name, ChatRole.class); + } + + public static Collection values() { + return values(ChatRole.class); + } + } +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/common/ChatGPTUtils.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/common/ChatGPTUtils.java new file mode 100644 index 0000000..e1fa121 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/common/ChatGPTUtils.java @@ -0,0 +1,98 @@ +package com.microsoft.openai.samples.assistant.common; + +import com.azure.ai.openai.models.*; +import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; +import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class ChatGPTUtils { + + public static ChatCompletionsOptions buildDefaultChatCompletionsOptions(List messages) { + ChatCompletionsOptions completionsOptions = new ChatCompletionsOptions(messages); + + completionsOptions.setMaxTokens(1024); + completionsOptions.setTemperature(0.1); + completionsOptions.setTopP(1.0); + //completionsOptions.setStop(new ArrayList<>(List.of("\n"))); + completionsOptions.setLogitBias(new HashMap<>()); + completionsOptions.setN(1); + completionsOptions.setStream(false); + completionsOptions.setUser("search-openai-demo-java"); + completionsOptions.setPresencePenalty(0.0); + completionsOptions.setFrequencyPenalty(0.0); + + return completionsOptions; + } + + private static final String IM_START_USER = "<|im_start|>user"; + private static final String IM_START_ASSISTANT = "<|im_start|>assistant"; + private static final String IM_START_SYSTEM = "<|im_start|>system"; + + public static String formatAsChatML(List messages) { + StringBuilder sb = new StringBuilder(); + messages.forEach(message -> { + String content = null; + if (message instanceof ChatRequestUserMessage) { + sb.append(IM_START_USER).append("\n"); + content = ((ChatRequestUserMessage) message).getContent().toString(); + } else if (message instanceof ChatRequestSystemMessage) { + sb.append(IM_START_SYSTEM).append("\n"); + content = ((ChatRequestSystemMessage) message).getContent(); + } else if (message instanceof ChatRequestAssistantMessage) { + sb.append(IM_START_ASSISTANT).append("\n"); + content = ((ChatRequestAssistantMessage) message).getContent(); + } + + if (content != null) { + sb.append(content).append("\n").append("|im_end|").append("\n"); + } + }); + return sb.toString(); + } + + public static List parseChatML(String chatML) { + List messages = new ArrayList<>(); + String[] messageTokens = chatML.split("\\|im_end\\|\\n"); + + for (String messageToken : messageTokens) { + String[] lines = messageToken.trim().split("\n"); + + if (lines.length >= 2) { + AuthorRole role = AuthorRole.SYSTEM; + if (IM_START_USER.equals(lines[0])) { + role = AuthorRole.USER; + } else if (IM_START_ASSISTANT.equals(lines[0])) { + role = AuthorRole.ASSISTANT; + } + + StringBuilder content = new StringBuilder(); + for (int i = 1; i < lines.length; ++i) { + content.append(lines[i]); + if (i < lines.length - 1) { + content.append("\n"); + } + } + + messages.add(new ChatMessageContent<>(role, content.toString())); + } + } + + return messages; + } + + public static String getLastUserQuestion(List messages) { + List userMessages = messages + .stream() + .filter(message -> message.role() == ChatGPTMessage.ChatRole.USER) + .toList(); + + if (!userMessages.isEmpty()) { + return userMessages.get(userMessages.size() - 1).content(); + } else { + return ""; + } + } +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/config/AzureAuthenticationConfiguration.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/config/AzureAuthenticationConfiguration.java new file mode 100644 index 0000000..a1dc228 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/config/AzureAuthenticationConfiguration.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.config; + +import com.azure.core.credential.TokenCredential; +import com.azure.identity.AzureCliCredentialBuilder; +import com.azure.identity.EnvironmentCredentialBuilder; +import com.azure.identity.ManagedIdentityCredentialBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +public class AzureAuthenticationConfiguration { + + @Value("${azure.identity.client-id}") + String clientId; + + @Profile("dev") + @Bean + public TokenCredential localTokenCredential() { + return new AzureCliCredentialBuilder().build(); + } + + @Profile("docker") + @Bean + public TokenCredential servicePrincipalTokenCredential() { + return new EnvironmentCredentialBuilder().build(); + } + + @Bean + @Profile("default") + public TokenCredential managedIdentityTokenCredential() { + if (this.clientId.equals("system-managed-identity")) + return new ManagedIdentityCredentialBuilder().build(); + else + return new ManagedIdentityCredentialBuilder().clientId(this.clientId).build(); + + } +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/config/DocumentIntelligenceConfiguration.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/config/DocumentIntelligenceConfiguration.java new file mode 100644 index 0000000..3983020 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/config/DocumentIntelligenceConfiguration.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.config; + +import com.azure.ai.documentintelligence.DocumentIntelligenceClient; +import com.azure.ai.documentintelligence.DocumentIntelligenceClientBuilder; +import com.azure.ai.openai.OpenAIAsyncClient; +import com.azure.ai.openai.OpenAIClient; +import com.azure.ai.openai.OpenAIClientBuilder; +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.credential.TokenCredential; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLogOptions; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class DocumentIntelligenceConfiguration { + + @Value("${documentintelligence.service}") + String documentIntelligenceServiceName; + + final TokenCredential tokenCredential; + + public DocumentIntelligenceConfiguration(TokenCredential tokenCredential) { + this.tokenCredential = tokenCredential; + } + + @Bean + public DocumentIntelligenceClient documentIntelligenceClient() { + String endpoint = "https://%s.cognitiveservices.azure.com".formatted(documentIntelligenceServiceName); + + return new DocumentIntelligenceClientBuilder() + .credential(tokenCredential) + .endpoint(endpoint) + .buildClient(); + } + +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/config/OpenAIConfiguration.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/config/OpenAIConfiguration.java new file mode 100644 index 0000000..9488d5a --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/config/OpenAIConfiguration.java @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.config; + +import com.azure.ai.openai.OpenAIAsyncClient; +import com.azure.ai.openai.OpenAIClient; +import com.azure.ai.openai.OpenAIClientBuilder; +import com.azure.core.credential.TokenCredential; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLogOptions; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class OpenAIConfiguration { + + @Value("${openai.service}") + String openAIServiceName; + + @Value("${openai.chatgpt.deployment}") + private String gptChatDeploymentModelId; + + final TokenCredential tokenCredential; + + public OpenAIConfiguration(TokenCredential tokenCredential) { + this.tokenCredential = tokenCredential; + } + + @Bean + @ConditionalOnProperty(name = "openai.tracing.enabled", havingValue = "true") + public OpenAIClient openAItracingEnabledClient() { + String endpoint = "https://%s.openai.azure.com".formatted(openAIServiceName); + + var httpLogOptions = new HttpLogOptions(); + // httpLogOptions.setPrettyPrintBody(true); + httpLogOptions.setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS); + + return new OpenAIClientBuilder() + .endpoint(endpoint) + .credential(tokenCredential) + .httpLogOptions(httpLogOptions) + .buildClient(); + } + + @Bean + @ConditionalOnProperty(name = "openai.tracing.enabled", havingValue = "false") + public OpenAIClient openAIDefaultClient() { + String endpoint = "https://%s.openai.azure.com".formatted(openAIServiceName); + return new OpenAIClientBuilder() + .endpoint(endpoint) + .credential(tokenCredential) + .buildClient(); + } + + @Bean + @ConditionalOnProperty(name = "openai.tracing.enabled", havingValue = "true") + public OpenAIAsyncClient tracingEnabledAsyncClient() { + String endpoint = "https://%s.openai.azure.com".formatted(openAIServiceName); + + var httpLogOptions = new HttpLogOptions(); + httpLogOptions.setPrettyPrintBody(true); + httpLogOptions.setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS); + + return new OpenAIClientBuilder() + .endpoint(endpoint) + .credential(tokenCredential) + .httpLogOptions(httpLogOptions) + .buildAsyncClient(); + } + + @Bean + @ConditionalOnProperty(name = "openai.tracing.enabled", havingValue = "false") + public OpenAIAsyncClient defaultAsyncClient() { + String endpoint = "https://%s.openai.azure.com".formatted(openAIServiceName); + return new OpenAIClientBuilder() + .endpoint(endpoint) + .credential(tokenCredential) + .buildAsyncClient(); + } +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatAppRequest.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatAppRequest.java new file mode 100644 index 0000000..0a50218 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatAppRequest.java @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.controller; + +import java.util.List; + +public record ChatAppRequest( + List messages, + ChatAppRequestContext context, + boolean stream, + String approach) {} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatAppRequestContext.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatAppRequestContext.java new file mode 100644 index 0000000..04f1cff --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatAppRequestContext.java @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.controller; + +public record ChatAppRequestContext(ChatAppRequestOverrides overrides) {} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatAppRequestOverrides.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatAppRequestOverrides.java new file mode 100644 index 0000000..2d10422 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatAppRequestOverrides.java @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.controller; + +public record ChatAppRequestOverrides( + boolean semantic_ranker, + boolean semantic_captions, + String exclude_category, + int top, + float temperature, + String prompt_template, + String prompt_template_prefix, + String prompt_template_suffix, + boolean suggest_followup_questions, + boolean use_oid_security_filter, + boolean use_groups_security_filter, + String semantic_kernel_mode) {} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatController.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatController.java new file mode 100644 index 0000000..3707a0a --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatController.java @@ -0,0 +1,104 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.controller; + +import com.azure.ai.documentintelligence.DocumentIntelligenceClient; +import com.azure.ai.openai.OpenAIAsyncClient; +import com.microsoft.openai.samples.assistant.agent.*; + + +import com.microsoft.openai.samples.assistant.proxy.BlobStorageProxy; +import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + + + +import java.util.List; + +@RestController +public class ChatController { + + private static final Logger LOGGER = LoggerFactory.getLogger(ChatController.class); + + private final IntentAgent intentAgent; + private final PaymentAgent paymentAgent; + private final HistoryReportingAgent historyReportingAgent; + + public ChatController(OpenAIAsyncClient openAIAsyncClient, DocumentIntelligenceClient documentIntelligenceClient, BlobStorageProxy blobStorageProxy, @Value("${openai.chatgpt.deployment}") String gptChatDeploymentModelId){ + this.intentAgent = new IntentAgent(openAIAsyncClient,gptChatDeploymentModelId); + this.paymentAgent = new PaymentAgent(openAIAsyncClient,gptChatDeploymentModelId,documentIntelligenceClient,blobStorageProxy); + this.historyReportingAgent = new HistoryReportingAgent(openAIAsyncClient,gptChatDeploymentModelId); + + } + + + @PostMapping(value = "/api/chat", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity openAIAsk(@RequestBody ChatAppRequest chatRequest) { + if (chatRequest.stream()) { + LOGGER.warn( + "Requested a content-type of application/json however also requested streaming." + + " Please use a content-type of application/ndjson"); + throw new ResponseStatusException( + HttpStatus.BAD_REQUEST, + "Requested a content-type of application/json however also requested streaming." + + " Please use a content-type of application/ndjson"); + } + + LOGGER.info("Received request for chat api with approach[{}]", chatRequest.approach()); + + if (chatRequest.messages() == null || chatRequest.messages().isEmpty()) { + LOGGER.warn("history cannot be null in Chat request"); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); + } + + ChatHistory chatHistory = convertSKChatHistory(chatRequest.messages()); + + LOGGER.info("Processing chat conversation..", chatHistory.getLastMessage().get().getContent()); + + IntentResponse response = intentAgent.run(chatHistory); + + LOGGER.info("Intent Type for chat conversation: {}", response.getIntentType()); + if (response.getIntentType() == IntentType.None) { + chatHistory.addAssistantMessage(response.getJsonData().get("clarify_sentence").toString()); + } + + + if (response.getIntentType() == IntentType.BillPayment || response.getIntentType() == IntentType.RepeatTransaction) { + var agentContext = paymentAgent.run(chatHistory); + chatHistory.addAssistantMessage(agentContext.getResult()); + } + + if (response.getIntentType() == IntentType.TransactionHistory) { + var agentContext = historyReportingAgent.run(chatHistory); + chatHistory.addAssistantMessage(agentContext.getResult()); + } + + return ResponseEntity.ok( + ChatResponse.buildChatResponse(chatHistory)); + } + + private ChatHistory convertSKChatHistory(List protocolChatHistory) { + ChatHistory chatHistory = new ChatHistory(false); + protocolChatHistory.forEach( + historyChat -> { + if("user".equals(historyChat.role())) + chatHistory.addUserMessage(historyChat.content()); + + if("assistant".equals(historyChat.role())) + chatHistory.addAssistantMessage(historyChat.content()); + }); + + return chatHistory; + + } +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatResponse.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatResponse.java new file mode 100644 index 0000000..ec1ee2a --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatResponse.java @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.controller; + + +import com.microsoft.openai.samples.assistant.common.ChatGPTMessage; +import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; + +import java.util.Collections; +import java.util.List; + +public record ChatResponse(List choices) { + + public static ChatResponse buildChatResponse(ChatHistory chatHistory) { + List dataPoints = Collections.emptyList(); + + + + String thoughts = ""; + + + return new ChatResponse( + List.of( + new ResponseChoice( + 0, + new ResponseMessage( + chatHistory.getLastMessage().get().getContent(), + ChatGPTMessage.ChatRole.ASSISTANT.toString()), + new ResponseContext(thoughts, dataPoints), + new ResponseMessage( + chatHistory.getLastMessage().get().getContent(), + ChatGPTMessage.ChatRole.ASSISTANT.toString())))); + } + +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ResponseChoice.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ResponseChoice.java new file mode 100644 index 0000000..448222e --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ResponseChoice.java @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.controller; + +public record ResponseChoice( + int index, ResponseMessage message, ResponseContext context, ResponseMessage delta) {} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ResponseContext.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ResponseContext.java new file mode 100644 index 0000000..f063fdd --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ResponseContext.java @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.controller; + +import java.util.List; + +public record ResponseContext(String thoughts, List data_points) {} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ResponseMessage.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ResponseMessage.java new file mode 100644 index 0000000..074cef1 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ResponseMessage.java @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.controller; + +public record ResponseMessage(String content, String role) {} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/auth/AuthSetup.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/auth/AuthSetup.java new file mode 100644 index 0000000..9e01deb --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/auth/AuthSetup.java @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.controller.auth; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class AuthSetup { + + @GetMapping("/api/auth_setup") + public String authSetup() { + return """ + { + "useLogin": false + } + """ + .stripIndent(); + } +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/content/ContentController.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/content/ContentController.java new file mode 100644 index 0000000..572d5cc --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/controller/content/ContentController.java @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.controller.content; + + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLConnection; + +import com.microsoft.openai.samples.assistant.proxy.BlobStorageProxy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.InputStreamResource; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.MimeTypeUtils; +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.RestController; + +@RestController +public class ContentController { + + private static final Logger LOGGER = LoggerFactory.getLogger(ContentController.class); + private final BlobStorageProxy blobStorageProxy; + + ContentController(BlobStorageProxy blobStorageProxy) { + this.blobStorageProxy = blobStorageProxy; + } + + @GetMapping("/api/content/{fileName}") + public ResponseEntity getContent(@PathVariable String fileName) { + LOGGER.info("Received request for content with name [{}] ]", fileName); + + if (!StringUtils.hasText(fileName)) { + LOGGER.warn("file name cannot be null"); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); + } + + String mimeType = URLConnection.guessContentTypeFromName(fileName); + + MediaType contentType = new MediaType(MimeTypeUtils.parseMimeType(mimeType)); + + InputStream fileInputStream; + + try { + fileInputStream = new ByteArrayInputStream(blobStorageProxy.getFileAsBytes(fileName)); + } catch (IOException ex) { + LOGGER.error("Cannot retrieve file [{}] from blob.{}", fileName, ex.getMessage()); + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.ok() + .header("Content-Disposition", "inline; filename=%s".formatted(fileName)) + .contentType(contentType) + .body(new InputStreamResource(fileInputStream)); + } +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/invoice/DocumentIntelligenceInvoiceScanHelper.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/invoice/DocumentIntelligenceInvoiceScanHelper.java new file mode 100644 index 0000000..db0eae7 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/invoice/DocumentIntelligenceInvoiceScanHelper.java @@ -0,0 +1,127 @@ +package com.microsoft.openai.samples.assistant.invoice; + + + +import com.azure.ai.documentintelligence.DocumentIntelligenceClient; +import com.azure.ai.documentintelligence.DocumentIntelligenceClientBuilder; +import com.azure.ai.documentintelligence.models.*; +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.util.polling.SyncPoller; +import com.microsoft.openai.samples.assistant.agent.HistoryReportingAgent; +import com.microsoft.openai.samples.assistant.proxy.BlobStorageProxy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; + +public class DocumentIntelligenceInvoiceScanHelper { + private static final Logger LOGGER = LoggerFactory.getLogger(DocumentIntelligenceInvoiceScanHelper.class); + + private final DocumentIntelligenceClient client; + + private final BlobStorageProxy blobStorageProxy; + + private final String modelId; + + public DocumentIntelligenceInvoiceScanHelper(DocumentIntelligenceClient client, BlobStorageProxy blobStorageProxy){ + this.client = client; + this.modelId = "prebuilt-invoice"; + this.blobStorageProxy = blobStorageProxy; + } + + public Map scan(String blobName) throws IOException { + + LOGGER.info("Retrieving blob file with name [{}]", blobName); + + byte[] blobData = blobStorageProxy.getFileAsBytes(blobName); + + LOGGER.info("Found blob file with name [{}] and size [{}]", blobName,blobData.length); + SyncPoller analyzeInvoicePoller = + client.beginAnalyzeDocument("prebuilt-invoice", + null, + null, + null, + null, + null, + null, new AnalyzeDocumentRequest().setBase64Source(blobStorageProxy.getFileAsBytes(blobName))); + + return internalScan(analyzeInvoicePoller); + + } + public Map scan (File file) throws IOException { + + SyncPoller analyzeInvoicePoller = + client.beginAnalyzeDocument("prebuilt-invoice", + null, + null, + null, + null, + null, + null, new AnalyzeDocumentRequest().setBase64Source(Files.readAllBytes(file.toPath()))); + + return internalScan(analyzeInvoicePoller); + + } + + private Map internalScan(SyncPoller analyzeInvoicePoller) { + AnalyzeResult analyzeInvoiceResult = analyzeInvoicePoller.getFinalResult().getAnalyzeResult(); + + LOGGER.info("Document intelligence analysis completed.Start extracting data.." ); + + Map scanData = new HashMap<>(); + + for (int i = 0; i < analyzeInvoiceResult.getDocuments().size(); i++) { + Document analyzedInvoice = analyzeInvoiceResult.getDocuments().get(i); + Map invoiceFields = analyzedInvoice.getFields(); + + DocumentField vendorNameField = invoiceFields.get("VendorName"); + if (vendorNameField != null) { + if (DocumentFieldType.STRING == vendorNameField.getType()) { + scanData.put("VendorName", vendorNameField.getValueString()); + } + } + + DocumentField vendorAddressField = invoiceFields.get("VendorAddress"); + if (vendorAddressField != null) { + scanData.put("VendorAddress", vendorAddressField.getContent()); + } + + DocumentField customerNameField = invoiceFields.get("CustomerName"); + if (customerNameField != null) { + scanData.put("CustomerName", customerNameField.getValueString()); + } + + DocumentField customerAddressRecipientField = invoiceFields.get("CustomerAddressRecipient"); + if (customerAddressRecipientField != null) { + scanData.put("CustomerAddressRecipient", customerAddressRecipientField.getValueString()); + } + + DocumentField invoiceIdField = invoiceFields.get("InvoiceId"); + if (invoiceIdField != null) { + scanData.put("InvoiceId", invoiceIdField.getValueString()); + } + + DocumentField invoiceDateField = invoiceFields.get("InvoiceDate"); + if (invoiceDateField != null) { + scanData.put("InvoiceDate", invoiceDateField.getValueDate().toString()); + + } + + DocumentField invoiceTotalField = invoiceFields.get("InvoiceTotal"); + if (invoiceTotalField != null) { + scanData.put("InvoiceTotal", invoiceTotalField.getContent()); + + } + + + + } + return scanData; + } + + +} \ No newline at end of file diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/InvoiceScanPlugin.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/InvoiceScanPlugin.java new file mode 100644 index 0000000..aded68f --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/InvoiceScanPlugin.java @@ -0,0 +1,89 @@ +package com.microsoft.openai.samples.assistant.plugin; + +import com.microsoft.openai.samples.assistant.agent.HistoryReportingAgent; +import com.microsoft.openai.samples.assistant.invoice.DocumentIntelligenceInvoiceScanHelper; +import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; +import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + + +/** + * reference: https://learn.microsoft.com/en-us/java/api/overview/azure/ai-openai-readme?view=azure-java-preview + * + * { + * "enhancements": { + * "ocr": { + * "enabled": true + * }, + * "grounding": { + * "enabled": true + * } + * }, + * "data_sources": [ + * { + * "type": "AzureComputerVision", + * "parameters": { + * "endpoint": "", + * "key": "" + * } + * }], + * "messages": [ + * { + * "role": "system", + * "content": "You are a helpful assistant." + * }, + * { + * "role": "user", + * "content": [ + * { + * "type": "text", + * "text": "Describe this picture:" + * }, + * { + * "type": "image_url", + * "image_url": { + * "url":"" + * } + * } + * ] + * } + * ], + * "max_tokens": 100, + * "stream": false + * } + */ +public class InvoiceScanPlugin { + + private static final Logger LOGGER = LoggerFactory.getLogger(InvoiceScanPlugin.class); + private final DocumentIntelligenceInvoiceScanHelper documentIntelligenceInvoiceScanHelper; + public InvoiceScanPlugin(DocumentIntelligenceInvoiceScanHelper documentIntelligenceInvoiceScanHelper) { + this.documentIntelligenceInvoiceScanHelper = documentIntelligenceInvoiceScanHelper; + } + @DefineKernelFunction(name = "scanInvoice", description = "Extract the invoice or bill data scanning a photo or image") + public String scanInvoice( + @KernelFunctionParameter(name = "filaPath", description = "the path to the file containing the image or photo") String filePath) { + + Map scanData = null; + + try{ + scanData = documentIntelligenceInvoiceScanHelper.scan(filePath); + } catch (Exception e) { + LOGGER.warn("Error extracting data from invoice {}:", filePath,e); + scanData = new HashMap<>(); + } + + LOGGER.info("Data extracted from invoice {}:{}", filePath,scanData); + return scanData.toString(); + + } + + + + +} + diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/PaymentPlugin.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/PaymentPlugin.java new file mode 100644 index 0000000..5b28797 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/PaymentPlugin.java @@ -0,0 +1,25 @@ +package com.microsoft.openai.samples.assistant.plugin; + +import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; +import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; + +import java.util.ArrayList; +import java.util.List; + +public class PaymentPlugin { + + + @DefineKernelFunction(name = "payBill", description = "Gets the last payment transactions based on the payee, recipient name") + public String submitBillPayment( + @KernelFunctionParameter(name = "recipientName", description = "Name of the payee, recipient") String recipientName, + @KernelFunctionParameter(name = "documentId", description = " the bill id or invoice number") String documentID, + @KernelFunctionParameter(name = "amount", description = "the total amount to pay") String amount) { + + System.out.println("Bill payment executed for recipient: " + recipientName + " with documentId: " + documentID + " and amount: " + amount); + + return "Payment Successful"; + + } + +} + diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/PaymentTransaction.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/PaymentTransaction.java new file mode 100644 index 0000000..9121ca0 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/PaymentTransaction.java @@ -0,0 +1,4 @@ +package com.microsoft.openai.samples.assistant.plugin; + +public record PaymentTransaction(String transactionId, String documentId, String recipientName, String amount, String transactionDatetime) {} + diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/TransactionHistoryPlugin.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/TransactionHistoryPlugin.java new file mode 100644 index 0000000..d836ad3 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/TransactionHistoryPlugin.java @@ -0,0 +1,40 @@ +package com.microsoft.openai.samples.assistant.plugin; + +import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; +import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +public class TransactionHistoryPlugin { + private static final Logger LOGGER = LoggerFactory.getLogger(TransactionHistoryPlugin.class); + private final TransactionService transactionService; + public TransactionHistoryPlugin(){ + this.transactionService = new TransactionService(); + } + + @DefineKernelFunction(name = "getTransactionsByRecepient", description = "Gets the last payment transactions based on the payee, recipient name") + public String getTransactionsByRecepient( + @KernelFunctionParameter(name = "recipientName", description = "Name of the payee, recipient") String recipientName) { + String transactionsByRecipient = transactionService.getTransactionsByRecipientName(recipientName).toString(); + LOGGER.info("Transactions for [{}]:{} ",recipientName,transactionsByRecipient); + return transactionsByRecipient; + + + } + + + @DefineKernelFunction(name = "getTransactions", description = "Gets the last payment transactions") + public String getTransactions() { + String lastTransactions = transactionService.getlastTransactions().toString(); + LOGGER.info("Last transactions:{} ",lastTransactions); + return lastTransactions; + + + } + + +} + diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/TransactionService.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/TransactionService.java new file mode 100644 index 0000000..e138b90 --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/TransactionService.java @@ -0,0 +1,51 @@ +package com.microsoft.openai.samples.assistant.plugin; + +import java.util.ArrayList; +import java.util.List; + +public class TransactionService { + + private List plumberTransactions = new ArrayList<>(); + + private List electricianTransactions = new ArrayList<>(); + + private List lastTransactions = new ArrayList<>(); + + public TransactionService(){ + + plumberTransactions.add(new PaymentTransaction("11", "0001", "Bill ThePlumber", "100.00", "2024-4-01T12:00:00Z")); + plumberTransactions.add(new PaymentTransaction("21", "0002", "Bill ThePlumber", "200.00", "2024-1-02T12:00:00Z")); + plumberTransactions.add(new PaymentTransaction("31", "0003", "Bill ThePlumber", "300.00", "2023-10-03T12:00:00Z")); + plumberTransactions.add(new PaymentTransaction("41", "0004", "Bill ThePlumber", "400.00", "2023-8-04T12:00:00Z")); + plumberTransactions.add(new PaymentTransaction("51", "0005", "Bill ThePlumber", "500.00", "2023-4-05T12:00:00Z")); + + + electricianTransactions.add(new PaymentTransaction("12", "0001", "Jane TheElectrician", "100.00", "2024-3-01T12:00:00Z")); + electricianTransactions.add(new PaymentTransaction("22", "0002", "Jane TheElectrician", "200.00", "2023-1-02T12:00:00Z")); + electricianTransactions.add(new PaymentTransaction("32", "0003", "Jane TheElectrician", "300.00", "2022-10-03T12:00:00Z")); + electricianTransactions.add(new PaymentTransaction("42", "0004", "Jane TheElectrician", "400.00", "2022-8-04T12:00:00Z")); + electricianTransactions.add(new PaymentTransaction("52", "0005", "Jane TheElectrician", "500.00", "2020-4-05T12:00:00Z")); + + + lastTransactions.add(new PaymentTransaction("11", "0001", "Bill ThePlumber", "100.00", "2024-4-01T12:00:00Z")); + lastTransactions.add(new PaymentTransaction("22", "0002", "Jane TheElectrician", "200.00", "2024-3-02T12:00:00Z")); + lastTransactions.add(new PaymentTransaction("33", "0003", "Bob TheCarpenter", "300.00", "2023-10-03T12:00:00Z")); + lastTransactions.add(new PaymentTransaction("43", "0004", "Alice ThePainter", "400.00", "2023-8-04T12:00:00Z")); + lastTransactions.add(new PaymentTransaction("53", "0005", "Charlie TheMechanic", "500.00", "2023-4-05T12:00:00Z")); + } + public List getTransactionsByRecipientName(String name) { + switch (name){ + case "Bill ThePlumber": + return plumberTransactions; + case "Jane TheElectrician": + return electricianTransactions; + default: + return lastTransactions; + } + } + + public List getlastTransactions() { + return lastTransactions; + } + +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/proxy/BlobStorageProxy.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/proxy/BlobStorageProxy.java new file mode 100644 index 0000000..dbf601e --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/proxy/BlobStorageProxy.java @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.proxy; + +import com.azure.core.credential.TokenCredential; +import com.azure.storage.blob.BlobContainerClient; +import com.azure.storage.blob.BlobContainerClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * This class is a proxy to the Blob storage API. It is responsible for: - calling the API - + * handling errors and retry strategy - add monitoring points - add circuit breaker with exponential + * backoff + */ +@Component +public class BlobStorageProxy { + + private final BlobContainerClient client; + + public BlobStorageProxy( + @Value("${storage-account.service}") String storageAccountServiceName, + @Value("${blob.container.name}") String containerName, + TokenCredential tokenCredential) { + + String endpoint = "https://%s.blob.core.windows.net".formatted(storageAccountServiceName); + this.client = + new BlobContainerClientBuilder() + .endpoint(endpoint) + .credential(tokenCredential) + .containerName(containerName) + .buildClient(); + } + + public byte[] getFileAsBytes(String fileName) throws IOException { + var blobClient = client.getBlobClient(fileName); + int dataSize = (int) blobClient.getProperties().getBlobSize(); + + // There is no need to close ByteArrayOutputStream. + // https://docs.oracle.com/javase/8/docs/api/java/io/ByteArrayOutputStream.html + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(dataSize); + blobClient.downloadStream(outputStream); + + return outputStream.toByteArray(); + } +} diff --git a/app/backend/src/main/java/com/microsoft/openai/samples/assistant/proxy/OpenAIProxy.java b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/proxy/OpenAIProxy.java new file mode 100644 index 0000000..182cd9d --- /dev/null +++ b/app/backend/src/main/java/com/microsoft/openai/samples/assistant/proxy/OpenAIProxy.java @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.openai.samples.assistant.proxy; + +import com.azure.ai.openai.OpenAIClient; +import com.azure.ai.openai.models.*; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.util.IterableStream; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ResponseStatusException; + +import java.util.List; + +/** + * This class is a proxy to the OpenAI API to simplify cross-cutting concerns management (security, + * load balancing, monitoring, resiliency). It is responsible for: - calling the OpenAI API - + * handling errors and retry strategy - load balance requests across open AI instances - add + * monitoring points - add circuit breaker with exponential backoff + * + *

It also makes unit testing easy using mockito to provide mock implementation for this bean. + */ +@Component +public class OpenAIProxy { + + private final OpenAIClient client; + + @Value("${openai.chatgpt.deployment}") + private String gptChatDeploymentModelId; + + @Value("${openai.embedding.deployment}") + private String embeddingDeploymentModelId; + + public OpenAIProxy(OpenAIClient client) { + this.client = client; + } + + public Completions getCompletions(CompletionsOptions completionsOptions) { + Completions completions; + try { + completions = client.getCompletions(this.gptChatDeploymentModelId, completionsOptions); + } catch (HttpResponseException e) { + throw new ResponseStatusException( + e.getResponse().getStatusCode(), "Error calling OpenAI API:" + e.getValue(), e); + } + return completions; + } + + public Completions getCompletions(String prompt) { + + Completions completions; + try { + completions = client.getCompletions(this.gptChatDeploymentModelId, prompt); + } catch (HttpResponseException e) { + throw new ResponseStatusException( + e.getResponse().getStatusCode(), + "Error calling OpenAI API:" + e.getMessage(), + e); + } + return completions; + } + + public ChatCompletions getChatCompletions(ChatCompletionsOptions chatCompletionsOptions) { + ChatCompletions chatCompletions; + try { + chatCompletions = + client.getChatCompletions( + this.gptChatDeploymentModelId, chatCompletionsOptions); + } catch (HttpResponseException e) { + throw new ResponseStatusException( + e.getResponse().getStatusCode(), + "Error calling OpenAI API:" + e.getMessage(), + e); + } + return chatCompletions; + } + + public IterableStream getChatCompletionsStream( + ChatCompletionsOptions chatCompletionsOptions) { + try { + return client.getChatCompletionsStream( + this.gptChatDeploymentModelId, chatCompletionsOptions); + } catch (HttpResponseException e) { + throw new ResponseStatusException( + e.getResponse().getStatusCode(), + "Error calling OpenAI API:" + e.getMessage(), + e); + } + } + + public Embeddings getEmbeddings(List texts) { + Embeddings embeddings; + try { + EmbeddingsOptions embeddingsOptions = new EmbeddingsOptions(texts); + embeddingsOptions.setUser("search-openai-demo-java"); + embeddingsOptions.setModel(this.embeddingDeploymentModelId); + embeddingsOptions.setInputType("query"); + embeddings = client.getEmbeddings(this.embeddingDeploymentModelId, embeddingsOptions); + } catch (HttpResponseException e) { + throw new ResponseStatusException( + e.getResponse().getStatusCode(), + "Error calling OpenAI API:" + e.getMessage(), + e); + } + return embeddings; + } +} diff --git a/app/backend/src/main/resources/application.properties b/app/backend/src/main/resources/application.properties new file mode 100644 index 0000000..2133743 --- /dev/null +++ b/app/backend/src/main/resources/application.properties @@ -0,0 +1,18 @@ +#Used to enable mocked class to take precedence over real class in unit tests +spring.main.lazy-initialization=true + +openai.service=${AZURE_OPENAI_SERVICE} +openai.chatgpt.deployment=${AZURE_OPENAI_CHATGPT_DEPLOYMENT:chat} +openai.tracing.enabled=${AZURE_OPENAI_TRACING_ENABLED:true} + +documentintelligence.service=${AZURE_DOCUMENT_INTELLIGENCE_SERVICE:example} + + +storage-account.service=${AZURE_STORAGE_ACCOUNT} +blob.container.name=${AZURE_STORAGE_CONTAINER:content} + +logging.level.com.microsoft.openai.samples.rag.ask.approaches.semantickernel=DEBUG +server.error.include-message=always + +# Support for User Assigned Managed identity +azure.identity.client-id=${AZURE_CLIENT_ID:system-managed-identity} \ No newline at end of file diff --git a/app/frontend/.dockerignore b/app/frontend/.dockerignore new file mode 100644 index 0000000..a1ee4db --- /dev/null +++ b/app/frontend/.dockerignore @@ -0,0 +1,2 @@ +manifests +node_modules \ No newline at end of file diff --git a/app/frontend/.env.dev b/app/frontend/.env.dev new file mode 100644 index 0000000..e34f261 --- /dev/null +++ b/app/frontend/.env.dev @@ -0,0 +1 @@ +VITE_BACKEND_URI=http://127.0.0.1:8081/api diff --git a/app/frontend/.env.local b/app/frontend/.env.local new file mode 100644 index 0000000..e34f261 --- /dev/null +++ b/app/frontend/.env.local @@ -0,0 +1 @@ +VITE_BACKEND_URI=http://127.0.0.1:8081/api diff --git a/app/frontend/.env.production b/app/frontend/.env.production new file mode 100644 index 0000000..c00db2d --- /dev/null +++ b/app/frontend/.env.production @@ -0,0 +1,2 @@ +VITE_BACKEND_URI=/api + diff --git a/app/frontend/.npmrc b/app/frontend/.npmrc new file mode 100644 index 0000000..b6f27f1 --- /dev/null +++ b/app/frontend/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/app/frontend/.prettierignore b/app/frontend/.prettierignore new file mode 100644 index 0000000..fc355bc --- /dev/null +++ b/app/frontend/.prettierignore @@ -0,0 +1,2 @@ +# Ignore JSON +**/*.json diff --git a/app/frontend/.prettierrc.json b/app/frontend/.prettierrc.json new file mode 100644 index 0000000..b7d6774 --- /dev/null +++ b/app/frontend/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "tabWidth": 4, + "printWidth": 160, + "arrowParens": "avoid", + "trailingComma": "none" +} diff --git a/app/frontend/Dockerfile b/app/frontend/Dockerfile new file mode 100644 index 0000000..670144c --- /dev/null +++ b/app/frontend/Dockerfile @@ -0,0 +1,21 @@ +FROM node:18-alpine AS build + +# make the 'app' folder the current working directory +WORKDIR /app + +COPY . . + + +# install project dependencies +RUN npm install +RUN npm run build + +FROM nginx:alpine + +WORKDIR /usr/share/nginx/html +COPY --from=build /app/build . +COPY --from=build /app/nginx/nginx.conf.template /etc/nginx/conf.d + +EXPOSE 80 + +CMD ["/bin/sh", "-c", "envsubst < /etc/nginx/conf.d/nginx.conf.template > /etc/nginx/conf.d/default.conf && nginx -g \"daemon off;\""] diff --git a/app/frontend/Dockerfile-aks b/app/frontend/Dockerfile-aks new file mode 100644 index 0000000..3041dbf --- /dev/null +++ b/app/frontend/Dockerfile-aks @@ -0,0 +1,20 @@ +FROM node:18-alpine AS build + +# make the 'app' folder the current working directory +WORKDIR /app + +COPY . . + + +# install project dependencies +RUN npm install +RUN npm run build + +FROM nginx:alpine + +WORKDIR /usr/share/nginx/html +COPY --from=build /app/build . + +EXPOSE 80 + +CMD ["/bin/sh", "-c", "nginx -g \"daemon off;\""] \ No newline at end of file diff --git a/app/frontend/index.html b/app/frontend/index.html new file mode 100644 index 0000000..e4081a0 --- /dev/null +++ b/app/frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + GPT + Enterprise data | Java Sample + + +

+ + + diff --git a/app/frontend/manifests/frontend-deployment.tmpl.yml b/app/frontend/manifests/frontend-deployment.tmpl.yml new file mode 100644 index 0000000..1eac564 --- /dev/null +++ b/app/frontend/manifests/frontend-deployment.tmpl.yml @@ -0,0 +1,26 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend-deployment + namespace: azure-open-ai + labels: + app: frontend +spec: + replicas: 1 + selector: + matchLabels: + app: frontend + template: + metadata: + labels: + app: frontend + spec: + containers: + - name: frontend + image: {{.Env.SERVICE_FRONTEND_IMAGE_NAME}} + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + envFrom: + - configMapRef: + name: azd-env-configmap diff --git a/app/frontend/manifests/frontend-service.yml b/app/frontend/manifests/frontend-service.yml new file mode 100644 index 0000000..2fabe3f --- /dev/null +++ b/app/frontend/manifests/frontend-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: frontend-service + namespace: azure-open-ai +spec: + type: ClusterIP + ports: + - protocol: TCP + port: 80 + targetPort: 80 + selector: + app: frontend diff --git a/app/frontend/nginx/nginx.conf.template b/app/frontend/nginx/nginx.conf.template new file mode 100644 index 0000000..cafa824 --- /dev/null +++ b/app/frontend/nginx/nginx.conf.template @@ -0,0 +1,13 @@ +server { + listen 80; + location / { + root /usr/share/nginx/html; + index index.html index.htm; + } + + location /api { + proxy_ssl_server_name on; + proxy_http_version 1.1; + proxy_pass $REACT_APP_API_BASE_URL; + } +} \ No newline at end of file diff --git a/app/frontend/package-lock.json b/app/frontend/package-lock.json new file mode 100644 index 0000000..f7a19b7 --- /dev/null +++ b/app/frontend/package-lock.json @@ -0,0 +1,5592 @@ +{ + "name": "frontend", + "version": "1.0.0-alpha", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "1.0.0-alpha", + "dependencies": { + "@azure/msal-browser": "^3.1.0", + "@azure/msal-react": "^2.0.4", + "@fluentui/react": "^8.112.5", + "@fluentui/react-components": "^9.37.3", + "@fluentui/react-icons": "^2.0.221", + "@react-spring/web": "^9.7.3", + "dompurify": "^3.0.6", + "ndjson-readablestream": "^1.0.7", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.18.0", + "scheduler": "^0.20.2" + }, + "devDependencies": { + "@types/dompurify": "^3.0.3", + "@types/react": "^18.2.34", + "@types/react-dom": "^18.2.14", + "@vitejs/plugin-react": "^4.1.1", + "prettier": "^3.0.3", + "typescript": "^5.2.2", + "vite": "^4.5.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.2.0.tgz", + "integrity": "sha512-le2qutddMiq0i3ErQaLKuwP1DpNgdd9iXPs3fSCsLuBrdGg9B4/j4ArCAHCwgxA82Ydj9BcqtMIL5BSWwU+P5A==", + "dependencies": { + "@azure/msal-common": "14.1.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.1.0.tgz", + "integrity": "sha512-xphmhcfl5VL+uq5//VKMwQn+wfEZLMKNpFCcMi8Ur8ej5UT166g6chBsxgMzc9xo9Y24R9FB3m/tjDiV03xMIA==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-react": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@azure/msal-react/-/msal-react-2.0.4.tgz", + "integrity": "sha512-BujRm5FBDWYXyr3pnmubS4dIqZMlurYVtV2AyztoeAFUd+nh3XQZD9knHBqTyu53IDjhCCvUPUke/jSkv5WGlg==", + "dependencies": { + "@rollup/plugin-typescript": "^11.1.0", + "rollup": "^3.20.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@azure/msal-browser": "^3.2.0", + "react": "^16.8.0 || ^17 || ^18" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", + "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz", + "integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", + "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", + "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", + "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", + "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.11.tgz", + "integrity": "sha512-q4qlUf5ucwbUJZXF5tEQ8LF7y0Nk4P58hOsGk3ucY0oCwgQqAnqXVbUuahCddVHfrxmpyewRpiTHwVHIETYu7Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.11.tgz", + "integrity": "sha512-snieiq75Z1z5LJX9cduSAjUr7vEI1OdlzFPMw0HH5YI7qQHDd3qs+WZoMrWYDsfRJSq36lIA6mfZBkvL46KoIw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.11.tgz", + "integrity": "sha512-iPuoxQEV34+hTF6FT7om+Qwziv1U519lEOvekXO9zaMMlT9+XneAhKL32DW3H7okrCOBQ44BMihE8dclbZtTuw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.11.tgz", + "integrity": "sha512-Gm0QkI3k402OpfMKyQEEMG0RuW2LQsSmI6OeO4El2ojJMoF5NLYb3qMIjvbG/lbMeLOGiW6ooU8xqc+S0fgz2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.11.tgz", + "integrity": "sha512-N15Vzy0YNHu6cfyDOjiyfJlRJCB/ngKOAvoBf1qybG3eOq0SL2Lutzz9N7DYUbb7Q23XtHPn6lMDF6uWbGv9Fw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.11.tgz", + "integrity": "sha512-atEyuq6a3omEY5qAh5jIORWk8MzFnCpSTUruBgeyN9jZq1K/QI9uke0ATi3MHu4L8c59CnIi4+1jDKMuqmR71A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.11.tgz", + "integrity": "sha512-XtuPrEfBj/YYYnAAB7KcorzzpGTvOr/dTtXPGesRfmflqhA4LMF0Gh/n5+a9JBzPuJ+CGk17CA++Hmr1F/gI0Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.11.tgz", + "integrity": "sha512-Idipz+Taso/toi2ETugShXjQ3S59b6m62KmLHkJlSq/cBejixmIydqrtM2XTvNCywFl3VC7SreSf6NV0i6sRyg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.11.tgz", + "integrity": "sha512-c6Vh2WS9VFKxKZ2TvJdA7gdy0n6eSy+yunBvv4aqNCEhSWVor1TU43wNRp2YLO9Vng2G+W94aRz+ILDSwAiYog==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.11.tgz", + "integrity": "sha512-S3hkIF6KUqRh9n1Q0dSyYcWmcVa9Cg+mSoZEfFuzoYXXsk6196qndrM+ZiHNwpZKi3XOXpShZZ+9dfN5ykqjjw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.11.tgz", + "integrity": "sha512-MRESANOoObQINBA+RMZW+Z0TJWpibtE7cPFnahzyQHDCA9X9LOmGh68MVimZlM9J8n5Ia8lU773te6O3ILW8kw==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.11.tgz", + "integrity": "sha512-qVyPIZrXNMOLYegtD1u8EBccCrBVshxMrn5MkuFc3mEVsw7CCQHaqZ4jm9hbn4gWY95XFnb7i4SsT3eflxZsUg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.11.tgz", + "integrity": "sha512-T3yd8vJXfPirZaUOoA9D2ZjxZX4Gr3QuC3GztBJA6PklLotc/7sXTOuuRkhE9W/5JvJP/K9b99ayPNAD+R+4qQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.11.tgz", + "integrity": "sha512-evUoRPWiwuFk++snjH9e2cAjF5VVSTj+Dnf+rkO/Q20tRqv+644279TZlPK8nUGunjPAtQRCj1jQkDAvL6rm2w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.11.tgz", + "integrity": "sha512-/SlRJ15XR6i93gRWquRxYCfhTeC5PdqEapKoLbX63PLCmAkXZHY2uQm2l9bN0oPHBsOw2IswRZctMYS0MijFcg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.11.tgz", + "integrity": "sha512-xcncej+wF16WEmIwPtCHi0qmx1FweBqgsRtEL1mSHLFR6/mb3GEZfLQnx+pUDfRDEM4DQF8dpXIW7eDOZl1IbA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.11.tgz", + "integrity": "sha512-aSjMHj/F7BuS1CptSXNg6S3M4F3bLp5wfFPIJM+Km2NfIVfFKhdmfHF9frhiCLIGVzDziggqWll0B+9AUbud/Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.11.tgz", + "integrity": "sha512-tNBq+6XIBZtht0xJGv7IBB5XaSyvYPCm1PxJ33zLQONdZoLVM0bgGqUrXnJyiEguD9LU4AHiu+GCXy/Hm9LsdQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.11.tgz", + "integrity": "sha512-kxfbDOrH4dHuAAOhr7D7EqaYf+W45LsAOOhAet99EyuxxQmjbk8M9N4ezHcEiCYPaiW8Dj3K26Z2V17Gt6p3ng==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.11.tgz", + "integrity": "sha512-Sh0dDRyk1Xi348idbal7lZyfSkjhJsdFeuC13zqdipsvMetlGiFQNdO+Yfp6f6B4FbyQm7qsk16yaZk25LChzg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.11.tgz", + "integrity": "sha512-o9JUIKF1j0rqJTFbIoF4bXj6rvrTZYOrfRcGyL0Vm5uJ/j5CkBD/51tpdxe9lXEDouhRgdr/BYzUrDOvrWwJpg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.11.tgz", + "integrity": "sha512-rQI4cjLHd2hGsM1LqgDI7oOCYbQ6IBOVsX9ejuRMSze0GqXUG2ekwiKkiBU1pRGSeCqFFHxTrcEydB2Hyoz9CA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.3.tgz", + "integrity": "sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==", + "dependencies": { + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/devtools": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/devtools/-/devtools-0.2.1.tgz", + "integrity": "sha512-8PHJLbD6VhBh+LJ1uty/Bz30qs02NXCE5u8WpOhSewlYXUWl03GNXknr9AS2yaAWJEQaY27x7eByJs44gODBcw==", + "peerDependencies": { + "@floating-ui/dom": ">=1.5.4" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.4.tgz", + "integrity": "sha512-jByEsHIY+eEdCjnTVu+E3ephzTOzkQ8hgUfGwos+bg7NlH33Zc5uO+QHz1mrQUOgIKKDD1RtS201P9NvAfq3XQ==", + "dependencies": { + "@floating-ui/core": "^1.5.3", + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, + "node_modules/@fluentui/date-time-utilities": { + "version": "8.5.16", + "resolved": "https://registry.npmjs.org/@fluentui/date-time-utilities/-/date-time-utilities-8.5.16.tgz", + "integrity": "sha512-l+mLfJ2VhdHjBpELLLPDaWgT7GMLynm2aqR7SttbEb6Jh7hc/7ck1MWm93RTb3gYVHYai8SENqimNcvIxHt/zg==", + "dependencies": { + "@fluentui/set-version": "^8.2.14", + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/dom-utilities": { + "version": "2.2.14", + "resolved": "https://registry.npmjs.org/@fluentui/dom-utilities/-/dom-utilities-2.2.14.tgz", + "integrity": "sha512-+4DVm5sNfJh+l8fM+7ylpOkGNZkNr4X1z1uKQPzRJ1PRhlnvc6vLpWNNicGwpjTbgufSrVtGKXwP5sf++r81lg==", + "dependencies": { + "@fluentui/set-version": "^8.2.14", + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/font-icons-mdl2": { + "version": "8.5.31", + "resolved": "https://registry.npmjs.org/@fluentui/font-icons-mdl2/-/font-icons-mdl2-8.5.31.tgz", + "integrity": "sha512-jioHZ9XUfR9vUT5XnxdCrJ+hoC9TpYim+4YdtlUE/euI8kdW1tDZ5zqlSNk1GLDR34n03R09yWj5gVDCcMJbyQ==", + "dependencies": { + "@fluentui/set-version": "^8.2.14", + "@fluentui/style-utilities": "^8.10.2", + "@fluentui/utilities": "^8.13.24", + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/foundation-legacy": { + "version": "8.2.51", + "resolved": "https://registry.npmjs.org/@fluentui/foundation-legacy/-/foundation-legacy-8.2.51.tgz", + "integrity": "sha512-z/jrp1imV66/D2MGpN/55LGk/Istymk5tN+XUFHDENDi+9zyb2MgSxFshp774DJIrg3vVlyuS8oo+dBuTM3UbQ==", + "dependencies": { + "@fluentui/merge-styles": "^8.5.15", + "@fluentui/set-version": "^8.2.14", + "@fluentui/style-utilities": "^8.10.2", + "@fluentui/utilities": "^8.13.24", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/keyboard-key": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@fluentui/keyboard-key/-/keyboard-key-0.4.14.tgz", + "integrity": "sha512-XzZHcyFEM20H23h3i15UpkHi2AhRBriXPGAHq0Jm98TKFppXehedjjEFuUsh+CyU5JKBhDalWp8TAQ1ArpNzow==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/keyboard-keys": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@fluentui/keyboard-keys/-/keyboard-keys-9.0.7.tgz", + "integrity": "sha512-vaQ+lOveQTdoXJYqDQXWb30udSfTVcIuKk1rV0X0eGAgcHeSDeP1HxMy+OgHOQZH3OiBH4ZYeWxb+tmfiDiygQ==", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/merge-styles": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/@fluentui/merge-styles/-/merge-styles-8.5.15.tgz", + "integrity": "sha512-4CdKwo4k1Un2QLulpSVIz/KMgLNBMgin4NPyapmKDMVuO1OOxJUqfocubRGNO5x9mKgAMMYwBKGO9i0uxMMpJw==", + "dependencies": { + "@fluentui/set-version": "^8.2.14", + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/priority-overflow": { + "version": "9.1.11", + "resolved": "https://registry.npmjs.org/@fluentui/priority-overflow/-/priority-overflow-9.1.11.tgz", + "integrity": "sha512-sdrpavvKX2kepQ1d6IaI3ObLq5SAQBPRHPGx2+wiMWL7cEx9vGGM0fmeicl3soqqmM5uwCmWnZk9QZv9XOY98w==", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/react": { + "version": "8.114.4", + "resolved": "https://registry.npmjs.org/@fluentui/react/-/react-8.114.4.tgz", + "integrity": "sha512-dVpfFSpWUxdyqWlCVSXX5d34S760h4MaQjGR2/TPavtcJRRpJDHbBN2Hn7s4riA6YX5N7bTdN372UvIVbBbzuw==", + "dependencies": { + "@fluentui/date-time-utilities": "^8.5.16", + "@fluentui/font-icons-mdl2": "^8.5.31", + "@fluentui/foundation-legacy": "^8.2.51", + "@fluentui/merge-styles": "^8.5.15", + "@fluentui/react-focus": "^8.8.38", + "@fluentui/react-hooks": "^8.6.36", + "@fluentui/react-portal-compat-context": "^9.0.11", + "@fluentui/react-window-provider": "^2.2.18", + "@fluentui/set-version": "^8.2.14", + "@fluentui/style-utilities": "^8.10.2", + "@fluentui/theme": "^2.6.41", + "@fluentui/utilities": "^8.13.24", + "@microsoft/load-themed-styles": "^1.10.26", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-accordion": { + "version": "9.3.38", + "resolved": "https://registry.npmjs.org/@fluentui/react-accordion/-/react-accordion-9.3.38.tgz", + "integrity": "sha512-BB8d9+Jr0v4SW58OJTIyvsxhA/iOBbvIkQZlVHKqt4tL8dHOIFPrApw5WqQqaSYJsEwt4HxmlNU4Dv8qRughbg==", + "dependencies": { + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": "^0.19.0 || ^0.20.0" + } + }, + "node_modules/@fluentui/react-alert": { + "version": "9.0.0-beta.104", + "resolved": "https://registry.npmjs.org/@fluentui/react-alert/-/react-alert-9.0.0-beta.104.tgz", + "integrity": "sha512-Z8BGSyzEKok5wlJF2cUc8GUj2q+c1D+119YF0WtHLiieh7pwOHjBcDJOHqnaVnQNbhetIA3NUht2z0e1wgOK5w==", + "dependencies": { + "@fluentui/react-avatar": "^9.6.9", + "@fluentui/react-button": "^9.3.65", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-aria": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@fluentui/react-aria/-/react-aria-9.7.3.tgz", + "integrity": "sha512-YwyPNEcBDCdY6YzhrIrtlSrLs2Le7X1jLq9em8OnqHeiO22dBmg5xlBJoAMwJ8awCpI9xhu1PhU/2VJY4YqNuA==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-utilities": "^9.16.1", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-avatar": { + "version": "9.6.9", + "resolved": "https://registry.npmjs.org/@fluentui/react-avatar/-/react-avatar-9.6.9.tgz", + "integrity": "sha512-3aZeUhGOg+UlHsp2x//G4VKRWKclcsZvX6L9UVnHsA/nQqRw7C5Bfo9iFNsEeJ3R5W5mFA6LyEFWedJ7QdAmdQ==", + "dependencies": { + "@fluentui/react-badge": "^9.2.22", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-popover": "^9.8.33", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-tooltip": "^9.4.11", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": "^0.19.0 || ^0.20.0" + } + }, + "node_modules/@fluentui/react-badge": { + "version": "9.2.22", + "resolved": "https://registry.npmjs.org/@fluentui/react-badge/-/react-badge-9.2.22.tgz", + "integrity": "sha512-zzimP5mZiiCOm8expUTzD6yvvKbnKq22PK/L6+oNpifrvQnDwJF/0nwXQVjA3+icNoYTaHe/q0fFivpXV+Js6g==", + "dependencies": { + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-breadcrumb": { + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/@fluentui/react-breadcrumb/-/react-breadcrumb-9.0.11.tgz", + "integrity": "sha512-L+AQqZz1gqkScD8IW1CjZWGNrDaHDc/gSv+PrvgSZeGDPibGj6TnLygJ7BKM+rQ+Hc2SbCogKbERpQZCbrSFvA==", + "dependencies": { + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-button": "^9.3.65", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-link": "^9.2.7", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-button": { + "version": "9.3.65", + "resolved": "https://registry.npmjs.org/@fluentui/react-button/-/react-button-9.3.65.tgz", + "integrity": "sha512-3VOt29AugkfR7VMnkKON449E7Sn/nvc6BBT4kJDGKQY+Nm5d2p9e4HmHp1UaM9zRPt47lagTY2WFJNrKKSe/BA==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-card": { + "version": "9.0.64", + "resolved": "https://registry.npmjs.org/@fluentui/react-card/-/react-card-9.0.64.tgz", + "integrity": "sha512-TB/Zk+tLDUPNyAd2y8BvN0T2nroimtBOpB5GTK72E5sWPk0kaKIHwBEfXxNFGdGXcw0TAmVNqYi4ks37vh0Rgg==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-checkbox": { + "version": "9.2.8", + "resolved": "https://registry.npmjs.org/@fluentui/react-checkbox/-/react-checkbox-9.2.8.tgz", + "integrity": "sha512-L4aWzeZdi98d0ZhgNPtxghfhasQv1qlxIRMaPxtwvk5TN6i9YmRF8vf5Pmf0PESjT+zp3VPcisHcIfcqG26SmQ==", + "dependencies": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-combobox": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-combobox/-/react-combobox-9.7.0.tgz", + "integrity": "sha512-YmTdg04rvsg2+Dkw3ob+YLnS9rm3TLVMMNYTH0T64/FM3qirHntIXGbhMZXP5Cdo14gzQwr/e78NjBRKfYO4Wg==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-positioning": "^9.12.4", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": "^0.19.0 || ^0.20.0" + } + }, + "node_modules/@fluentui/react-components": { + "version": "9.45.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-components/-/react-components-9.45.0.tgz", + "integrity": "sha512-Y+Laj1dvRcCp/nWT0DExRXoh7oKTX458g6oltrGjhIHikq4D6/kssK5tfhCyknPLwIlVSYi5J+G6L3NfvI8a8w==", + "dependencies": { + "@fluentui/react-accordion": "^9.3.38", + "@fluentui/react-alert": "9.0.0-beta.104", + "@fluentui/react-avatar": "^9.6.9", + "@fluentui/react-badge": "^9.2.22", + "@fluentui/react-breadcrumb": "^9.0.11", + "@fluentui/react-button": "^9.3.65", + "@fluentui/react-card": "^9.0.64", + "@fluentui/react-checkbox": "^9.2.8", + "@fluentui/react-combobox": "^9.7.0", + "@fluentui/react-dialog": "^9.9.7", + "@fluentui/react-divider": "^9.2.58", + "@fluentui/react-drawer": "^9.1.1", + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-image": "^9.1.55", + "@fluentui/react-infobutton": "9.0.0-beta.88", + "@fluentui/react-infolabel": "^9.0.16", + "@fluentui/react-input": "^9.4.60", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-link": "^9.2.7", + "@fluentui/react-menu": "^9.12.45", + "@fluentui/react-message-bar": "^9.0.16", + "@fluentui/react-overflow": "^9.1.8", + "@fluentui/react-persona": "^9.2.68", + "@fluentui/react-popover": "^9.8.33", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-positioning": "^9.12.4", + "@fluentui/react-progress": "^9.1.60", + "@fluentui/react-provider": "^9.13.8", + "@fluentui/react-radio": "^9.2.3", + "@fluentui/react-select": "^9.1.60", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-skeleton": "^9.0.48", + "@fluentui/react-slider": "^9.1.65", + "@fluentui/react-spinbutton": "^9.2.60", + "@fluentui/react-spinner": "^9.3.38", + "@fluentui/react-switch": "^9.1.65", + "@fluentui/react-table": "^9.11.5", + "@fluentui/react-tabs": "^9.4.6", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-tags": "^9.0.22", + "@fluentui/react-text": "^9.4.7", + "@fluentui/react-textarea": "^9.3.60", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-toast": "^9.3.27", + "@fluentui/react-toolbar": "^9.1.66", + "@fluentui/react-tooltip": "^9.4.11", + "@fluentui/react-tree": "^9.4.25", + "@fluentui/react-utilities": "^9.16.1", + "@fluentui/react-virtualizer": "9.0.0-alpha.66", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": "^0.19.0 || ^0.20.0" + } + }, + "node_modules/@fluentui/react-context-selector": { + "version": "9.1.49", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.49.tgz", + "integrity": "sha512-u4wRNfnyfuZDalVEESBPFQ0Ue4yYu+ozkPQvuEV6kriQGnAQQyyVbIidOCuP7Sja0nBwgM8eAzK0uX/slmmj3Q==", + "dependencies": { + "@fluentui/react-utilities": "^9.16.1", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": "^0.19.0 || ^0.20.0" + } + }, + "node_modules/@fluentui/react-dialog": { + "version": "9.9.7", + "resolved": "https://registry.npmjs.org/@fluentui/react-dialog/-/react-dialog-9.9.7.tgz", + "integrity": "sha512-5/6MeaHOYpx8Vt0auMJGLCjn6O1IYtl6IhwdwRNXL6AS1o4F24IKXdWZPtiHWuvzbuZAQd3+5nRDUE5KC9We6A==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "react-transition-group": "^4.4.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-divider": { + "version": "9.2.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-divider/-/react-divider-9.2.58.tgz", + "integrity": "sha512-y1ECy1zM4imKhpyOyUGugB+J30tfySO5hhrsIcpaiUQxRjE4IhZf2ZG6EqAQYLinJ+hV06yLZoazekljlvk6yw==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-drawer": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-drawer/-/react-drawer-9.1.1.tgz", + "integrity": "sha512-3zvbbeaLLJZa4MXRpW8Ta4DFZ5457Tq9/4a0CqsIW/+8EuwtJwO+FB5a0DS6j0q6kN4mjkWF19OvzMkJsSTRVw==", + "dependencies": { + "@fluentui/react-dialog": "^9.9.7", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-motion-preview": "^0.5.10", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-field": { + "version": "9.1.50", + "resolved": "https://registry.npmjs.org/@fluentui/react-field/-/react-field-9.1.50.tgz", + "integrity": "sha512-2mbx7YReMWvrgi3set9KepLLgMyNJ7StLu/HiHMM3jkcgPt3mGfwoJEsEKt+xd8eUAo4b82F7t+tHI4f9yzJaQ==", + "dependencies": { + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-focus": { + "version": "8.8.38", + "resolved": "https://registry.npmjs.org/@fluentui/react-focus/-/react-focus-8.8.38.tgz", + "integrity": "sha512-vnsaY7hJSPIJBxm5Pj0FrcFDumV6kKgFVpsKsEKJzb1D88rDDLcmvz9jWUx68a3ru6idEbZYmyePGT1IiRsAug==", + "dependencies": { + "@fluentui/keyboard-key": "^0.4.14", + "@fluentui/merge-styles": "^8.5.15", + "@fluentui/set-version": "^8.2.14", + "@fluentui/style-utilities": "^8.10.2", + "@fluentui/utilities": "^8.13.24", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-hooks": { + "version": "8.6.36", + "resolved": "https://registry.npmjs.org/@fluentui/react-hooks/-/react-hooks-8.6.36.tgz", + "integrity": "sha512-kI0Z4Q4xHUs4SOmmI5n5OH5fPckqMSCovTRpiuxzCO2TNzLmfC861+nqf4Ygw/ChqNm2gWNZZfUADfnNAEsq+Q==", + "dependencies": { + "@fluentui/react-window-provider": "^2.2.18", + "@fluentui/set-version": "^8.2.14", + "@fluentui/utilities": "^8.13.24", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-icons": { + "version": "2.0.225", + "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.225.tgz", + "integrity": "sha512-L9phN3bAMlZCa5+/ObGjIO+5GI8M50ym766sraSq92jaJwgAXrCJDLWuDGWZRGrC63DcagtR2culptj3q7gMMg==", + "dependencies": { + "@griffel/react": "^1.0.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-image": { + "version": "9.1.55", + "resolved": "https://registry.npmjs.org/@fluentui/react-image/-/react-image-9.1.55.tgz", + "integrity": "sha512-hYP61OWLuGSJNPOGJXtphbiDESfLB+/vsODKQsJhrDRJ2CSNMAfNznPHucqGRRN6AWQOI/BynJDS5F22Y//7CQ==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-infobutton": { + "version": "9.0.0-beta.88", + "resolved": "https://registry.npmjs.org/@fluentui/react-infobutton/-/react-infobutton-9.0.0-beta.88.tgz", + "integrity": "sha512-NVZyfrLtoFNu7cGkp2ORWsxJiCk1JgN4CVBDj03QSIh14EsPMwphYgDwfQ8TZOF2Nub0DGtC7/tF8IUlb/aP6g==", + "dependencies": { + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-popover": "^9.8.33", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-infolabel": { + "version": "9.0.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-infolabel/-/react-infolabel-9.0.16.tgz", + "integrity": "sha512-UCY+2vB4vOn0LfVhbgkyNG0EiuKIe0PdxEAtLU2PqosHLkaLKnYDKJdiIS/oaFmyNtGHmMxRkigvZpZ7h74f9g==", + "dependencies": { + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-popover": "^9.8.33", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-input": { + "version": "9.4.60", + "resolved": "https://registry.npmjs.org/@fluentui/react-input/-/react-input-9.4.60.tgz", + "integrity": "sha512-kuk24K0X0gckTCssXoiWvZsTFVpZJv+WPl2fkjxeffzmFfBZtJUFQkXeC4/hcAg+aScjZnEtqjHjwDEbjZqkeA==", + "dependencies": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-jsx-runtime": { + "version": "9.0.27", + "resolved": "https://registry.npmjs.org/@fluentui/react-jsx-runtime/-/react-jsx-runtime-9.0.27.tgz", + "integrity": "sha512-9wxsWxVI7RLXsdK+7lzp7TK0FJKnrrj+Igxn0prqAvXdBRiFcuycoCJaHzC4Ka+Hsiol8NQg6xaIR59a28lmyQ==", + "dependencies": { + "@fluentui/react-utilities": "^9.16.1", + "@swc/helpers": "^0.5.1", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-label": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-label/-/react-label-9.1.58.tgz", + "integrity": "sha512-0ouSMop4vpXJzMvAyfmIr3TgDM/W1k+GFm8ZPD5fDQCopSJ+h3kvUZg5pqaXpBwamvZ16+qRARfTNITp2U7Rjw==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-link": { + "version": "9.2.7", + "resolved": "https://registry.npmjs.org/@fluentui/react-link/-/react-link-9.2.7.tgz", + "integrity": "sha512-z4X9dcUc/7FlqDxbGKbOfWubru+QimtzgMtlVxZ30pkC959hfIbFpbBY6Me76UOuFiOZxUPdfyY/73ekhhhVxw==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-menu": { + "version": "9.12.45", + "resolved": "https://registry.npmjs.org/@fluentui/react-menu/-/react-menu-9.12.45.tgz", + "integrity": "sha512-qhpmuvAB4DUmmC5lNMakVvZjTdj/GZnH6WctNGZp94iCZLhcnIQcM9l0PvRpUpU1v3irXRyE5QV+x+wXC0awTw==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-positioning": "^9.12.4", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": "^0.19.0 || ^0.20.0" + } + }, + "node_modules/@fluentui/react-message-bar": { + "version": "9.0.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-message-bar/-/react-message-bar-9.0.16.tgz", + "integrity": "sha512-R1VnqcFwu0pM2Yk8rjkN48Lx/n44UFD13BuY8/JeEuU8XQ8hLnEBVtdHjzRPJk+iM5in2ScMMQj4Z0nWyCRM1Q==", + "dependencies": { + "@fluentui/react-button": "^9.3.65", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "react-transition-group": "^4.4.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-motion-preview": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@fluentui/react-motion-preview/-/react-motion-preview-0.5.10.tgz", + "integrity": "sha512-6iwF3N4hB6IxCoFVusgA2mp6mrTknwcsVGNYEQw1YF5WgGOMF3M0N1xNpN61/SYziT6HSUaI38NaA7LI3Dp3Sw==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-overflow": { + "version": "9.1.8", + "resolved": "https://registry.npmjs.org/@fluentui/react-overflow/-/react-overflow-9.1.8.tgz", + "integrity": "sha512-W8L68+0bUtfGr72LRx+U05EZLO0E8VMfscDiNKiEjDrOqdBnqNAIDN86825wrN77HH2wvILN07EhPOauqzz8YQ==", + "dependencies": { + "@fluentui/priority-overflow": "^9.1.11", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": "^0.19.0 || ^0.20.0" + } + }, + "node_modules/@fluentui/react-persona": { + "version": "9.2.68", + "resolved": "https://registry.npmjs.org/@fluentui/react-persona/-/react-persona-9.2.68.tgz", + "integrity": "sha512-CYtDiZ34GGaw7lZ85uHZOuYXzkY21VHN6cUlGY1TJn98+Xz+y7JoVLIG7KZHHp2JzmmjtwjvgnqAdOun5LrWig==", + "dependencies": { + "@fluentui/react-avatar": "^9.6.9", + "@fluentui/react-badge": "^9.2.22", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-popover": { + "version": "9.8.33", + "resolved": "https://registry.npmjs.org/@fluentui/react-popover/-/react-popover-9.8.33.tgz", + "integrity": "sha512-0yPX6KCdMEGmrvJnQles5iTKN0OZ2vNSPVdkbyEKIUKj5DrNK1cMZEV/7Tgrtn922fx3/74FLMqEpEDTdrvQ/Q==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-positioning": "^9.12.4", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": "^0.19.0 || ^0.20.0" + } + }, + "node_modules/@fluentui/react-portal": { + "version": "9.4.10", + "resolved": "https://registry.npmjs.org/@fluentui/react-portal/-/react-portal-9.4.10.tgz", + "integrity": "sha512-k8fTRv9wTPSPCuNBFE2HxIhXsVYoG6Azb6Ib2xaDK+nczoW2WbsmNmwBJGEGi8UKjIoQzV+95KsYQ9me+uqKPA==", + "dependencies": { + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "use-disposable": "^1.0.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-portal-compat-context": { + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/@fluentui/react-portal-compat-context/-/react-portal-compat-context-9.0.11.tgz", + "integrity": "sha512-ubvW/ej0O+Pago9GH3mPaxzUgsNnBoqvghNamWjyKvZIViyaXUG6+sgcAl721R+qGAFac+A20akI5qDJz/xtdg==", + "dependencies": { + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-positioning": { + "version": "9.12.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-positioning/-/react-positioning-9.12.4.tgz", + "integrity": "sha512-qQAjHF/FJFs2TyK0x08t0iFtDQlGNGH0OFC3jrG1xIFEe3nFPoeYeNT3zxOmj+D7bvlcJTIITcoe++YQTnCf4w==", + "dependencies": { + "@floating-ui/devtools": "0.2.1", + "@floating-ui/dom": "^1.2.0", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-progress": { + "version": "9.1.60", + "resolved": "https://registry.npmjs.org/@fluentui/react-progress/-/react-progress-9.1.60.tgz", + "integrity": "sha512-9wC7lWdo3S8rhxKWlIhcYAzsZNw+rL2HvNJTvEvFxXcOG7nJxP/3mGclV/jCCwDoPDnt9BT+40pGK84eD0BNIA==", + "dependencies": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-provider": { + "version": "9.13.8", + "resolved": "https://registry.npmjs.org/@fluentui/react-provider/-/react-provider-9.13.8.tgz", + "integrity": "sha512-FCvDMjs/BNAcqJuHU+kN/lqLB2RDQ/LQo29ltfLKFlTR1nTUNJvPMOVhjj6eEt+t81628LOYhbbaXOj9rYtfGg==", + "dependencies": { + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/core": "^1.14.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-radio": { + "version": "9.2.3", + "resolved": "https://registry.npmjs.org/@fluentui/react-radio/-/react-radio-9.2.3.tgz", + "integrity": "sha512-8eKeUL0ZNr792Q6NGWPp7dpOV2IFcjAQ2oWR2/bruQVu8LMzYYKe2o6pQWdCag6UGPZuszkms9Xl7zPdDQBUdA==", + "dependencies": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": "^0.19.0 || ^0.20.0" + } + }, + "node_modules/@fluentui/react-select": { + "version": "9.1.60", + "resolved": "https://registry.npmjs.org/@fluentui/react-select/-/react-select-9.1.60.tgz", + "integrity": "sha512-4HfRRTlGStOgtO00RY6jmOwz6MXnoa9gtjkV7StLmJZ2U5NTjVUrnp2dP1Vjb6hO13xaihWGEYyYKnsQ3R7kIw==", + "dependencies": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-shared-contexts": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-shared-contexts/-/react-shared-contexts-9.14.0.tgz", + "integrity": "sha512-P9yhg31WYfB1W66/gD3+qVCLBsyIEcOzQvKVaIQvd9UhF67lNW4kMXUB6YVOk5PV0Og4hXnkH/vuHl7YMD9RHw==", + "dependencies": { + "@fluentui/react-theme": "^9.1.16", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-skeleton": { + "version": "9.0.48", + "resolved": "https://registry.npmjs.org/@fluentui/react-skeleton/-/react-skeleton-9.0.48.tgz", + "integrity": "sha512-P0Rw5hIOn5CrZIWg7nVoK3gamxFhZI80KcRVaWap4O3gLo5C8nKHJWOtyBQZ5WKH+S6hoEGZ2USL6CoyXslxeQ==", + "dependencies": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-slider": { + "version": "9.1.65", + "resolved": "https://registry.npmjs.org/@fluentui/react-slider/-/react-slider-9.1.65.tgz", + "integrity": "sha512-7kuJMIojxCmNOuiRmQwh9iiXx8zwxkrgvsWmReRIBX0WB6w1VqMcuuikq2Z2ISgNPmepCX8W+qDfx8Ne4F/HtQ==", + "dependencies": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-spinbutton": { + "version": "9.2.60", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinbutton/-/react-spinbutton-9.2.60.tgz", + "integrity": "sha512-0IIxEH0CTf4fNMoyvMa37bc63+0ZlznlsNy8lF3hujAT8Z9sUKVMH68e6tGUuXGJIkCUyDKU8HA+9FF2DyPvNA==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-spinner": { + "version": "9.3.38", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinner/-/react-spinner-9.3.38.tgz", + "integrity": "sha512-dPJr7/rgU2Qe/K2BciJTAEwEd0ytGpCw3VOVyK2T25w7Jw5RAHmgP+mbw+7se44Mr6sd1LH76mh5sfmQ3tODgw==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-switch": { + "version": "9.1.65", + "resolved": "https://registry.npmjs.org/@fluentui/react-switch/-/react-switch-9.1.65.tgz", + "integrity": "sha512-P0DwogD6hZJ3O005zCFPDoFXuzkrpKMrAeQGh9X0fqFP5JyHXVCgAAZQOLcphbbT9QukoEF5irN2Z4L9gBn57A==", + "dependencies": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-table": { + "version": "9.11.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-table/-/react-table-9.11.5.tgz", + "integrity": "sha512-roQRITOtl1aqXlachS2oTraVE45x3KdDrX0KyQGCdcQRxNprXJW6dIK9QjlbAL6yAsAMDafmFA4y9uRxl408dQ==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-avatar": "^9.6.9", + "@fluentui/react-checkbox": "^9.2.8", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-radio": "^9.2.3", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tabs": { + "version": "9.4.6", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabs/-/react-tabs-9.4.6.tgz", + "integrity": "sha512-LQvibLeJFyqKKiOjZUkRvbfLtsVosUhNUdh1SCQUPxQVpEPSK6XgwK0A1+jjoVhKn+PAJakxRINgnvqQD8pQBA==", + "dependencies": { + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": "^0.19.0 || ^0.20.0" + } + }, + "node_modules/@fluentui/react-tabster": { + "version": "9.17.3", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabster/-/react-tabster-9.17.3.tgz", + "integrity": "sha512-cFcUYrkGW15w5yXzCPTTVG/7x5kNXxnhQXuh8SPyCc9JZeG7XI3+hy1T37PsXGxNS4KN9ePHkBHzgDfYO4gzYQ==", + "dependencies": { + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "keyborg": "^2.3.0", + "tabster": "^5.0.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tags": { + "version": "9.0.22", + "resolved": "https://registry.npmjs.org/@fluentui/react-tags/-/react-tags-9.0.22.tgz", + "integrity": "sha512-gQIOCVu3HIfGjtAmwOnwBEnTsNyRBU8Pvs6EugpUyyqkRjzbm5TnL3LtiUy4f6/+NuaRqcYAvhwpdUhrlciwcA==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-avatar": "^9.6.9", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-text": { + "version": "9.4.7", + "resolved": "https://registry.npmjs.org/@fluentui/react-text/-/react-text-9.4.7.tgz", + "integrity": "sha512-c6uJ98B35L8sviYxhQj1i+LW+HVNDdco2ImS9VLv/Duo4HiYs1G2y1YhtBDDiGxLe2moIvfg9ajDzMZV29aXFw==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-textarea": { + "version": "9.3.60", + "resolved": "https://registry.npmjs.org/@fluentui/react-textarea/-/react-textarea-9.3.60.tgz", + "integrity": "sha512-wH4MBWT4EOgNH9FXTjcgH34oANUaoduhmVjffnxaPl3R767Ak0fZPG7kky7yrLMjTDUSwILsEj/q+hsN6o+7Ag==", + "dependencies": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-theme": { + "version": "9.1.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-theme/-/react-theme-9.1.16.tgz", + "integrity": "sha512-QK2dGE5aQXN1UGdiEmGKpYGP3tHXIchLvFf8DEEOWnF4XBc9SiEPNFYkvLMJjHxZmDz4D670rsOPe0r5jFDEKQ==", + "dependencies": { + "@fluentui/tokens": "1.0.0-alpha.13", + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/react-toast": { + "version": "9.3.27", + "resolved": "https://registry.npmjs.org/@fluentui/react-toast/-/react-toast-9.3.27.tgz", + "integrity": "sha512-DbRAYyL5Bd/pcFiGHPpK+rQMyc4LBll9YBy496l97dGDO2HmqFuiwP74V1KznxLcr4inCNWwThIJws5VLFsJLg==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "react-transition-group": "^4.4.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-toolbar": { + "version": "9.1.66", + "resolved": "https://registry.npmjs.org/@fluentui/react-toolbar/-/react-toolbar-9.1.66.tgz", + "integrity": "sha512-ooNTp1R5MBZwiVK8fiJu29gE48vUx4NbXdwB2yHcCprasG3asjuoKQfOYM4+1NfFA0DetVrbK8L46IBeZyeBvA==", + "dependencies": { + "@fluentui/react-button": "^9.3.65", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-divider": "^9.2.58", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-radio": "^9.2.3", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tooltip": { + "version": "9.4.11", + "resolved": "https://registry.npmjs.org/@fluentui/react-tooltip/-/react-tooltip-9.4.11.tgz", + "integrity": "sha512-HXm8yYuAHJuczeFExco0WQSjO3DzDj5AJxqICHF8qtbtihUKfWpPnKM1qQWR+yJR2zc2jzvOEIzZXEkxSG+fSg==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-positioning": "^9.12.4", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tree": { + "version": "9.4.25", + "resolved": "https://registry.npmjs.org/@fluentui/react-tree/-/react-tree-9.4.25.tgz", + "integrity": "sha512-7IMqnOiNFMRuPujnbxJUYD8AEh0z1OGXkdNkAeLyj3pkwuvQs9+TbaNtv5Z372YN+kwYF4EYalYcPuNsRlx7cQ==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-avatar": "^9.6.9", + "@fluentui/react-button": "^9.3.65", + "@fluentui/react-checkbox": "^9.2.8", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-radio": "^9.2.3", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-utilities": { + "version": "9.16.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-utilities/-/react-utilities-9.16.1.tgz", + "integrity": "sha512-2wdwmgTFcVy14ZLbRNJ8Q6dCCBLekkJ8Znnok68gKRLDcwpPT3UjSraoU+DGjOA5BMfPppZBU8Yb5GqdIfd48g==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-shared-contexts": "^9.14.0", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-virtualizer": { + "version": "9.0.0-alpha.66", + "resolved": "https://registry.npmjs.org/@fluentui/react-virtualizer/-/react-virtualizer-9.0.0-alpha.66.tgz", + "integrity": "sha512-x/ZOAIAwctt7pvOBIzS4iZGU0ahiPhQFS7iAHksFkF9LimneaV92A/02dW0Cy4v7dv9wZNoosQwhS05Yx3DVDQ==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-window-provider": { + "version": "2.2.18", + "resolved": "https://registry.npmjs.org/@fluentui/react-window-provider/-/react-window-provider-2.2.18.tgz", + "integrity": "sha512-nBKqxd0P8NmIR0qzFvka1urE2LVbUm6cse1I1T7TcOVNYa5jDf5BrO06+JRZfwbn00IJqOnIVoP0qONqceypWQ==", + "dependencies": { + "@fluentui/set-version": "^8.2.14", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/set-version": { + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@fluentui/set-version/-/set-version-8.2.14.tgz", + "integrity": "sha512-f/QWJnSeyfAjGAqq57yjMb6a5ejPlwfzdExPmzFBuEOuupi8hHbV8Yno12XJcTW4I0KXEQGw+PUaM1aOf/j7jw==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/style-utilities": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/@fluentui/style-utilities/-/style-utilities-8.10.2.tgz", + "integrity": "sha512-ocELtMb/85nBa3rSfiAIwYx6TydN+3rQqv1P0H/L7etYNNtxOfS86JSWfn8zAsHMejbwUKJ1ZsIKs47c598XGQ==", + "dependencies": { + "@fluentui/merge-styles": "^8.5.15", + "@fluentui/set-version": "^8.2.14", + "@fluentui/theme": "^2.6.41", + "@fluentui/utilities": "^8.13.24", + "@microsoft/load-themed-styles": "^1.10.26", + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/theme": { + "version": "2.6.41", + "resolved": "https://registry.npmjs.org/@fluentui/theme/-/theme-2.6.41.tgz", + "integrity": "sha512-h9RguEzqzJ0+59ys5Kkp7JtsjhDUxBLmQunu5rpHp5Mp788OtEjI/n1a9FIcOAL/priPSQwXN7RbuDpeP7+aSw==", + "dependencies": { + "@fluentui/merge-styles": "^8.5.15", + "@fluentui/set-version": "^8.2.14", + "@fluentui/utilities": "^8.13.24", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/tokens": { + "version": "1.0.0-alpha.13", + "resolved": "https://registry.npmjs.org/@fluentui/tokens/-/tokens-1.0.0-alpha.13.tgz", + "integrity": "sha512-IzYysTTBkAH7tQZxYKpzhxYnTJkvwXhjhTOpmERgnqTFifHTP8/vaQjJAAm7dI/9zlDx1oN+y/I+KzL9bDLHZQ==", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/utilities": { + "version": "8.13.24", + "resolved": "https://registry.npmjs.org/@fluentui/utilities/-/utilities-8.13.24.tgz", + "integrity": "sha512-/jo6hWCzTGCx06l2baAMwsjjBZ/dyMouls53uNaQLUGUUhUwXh/DcDDXMqLRJB3MaH9zvgfvRw61iKmm2s9fIA==", + "dependencies": { + "@fluentui/dom-utilities": "^2.2.14", + "@fluentui/merge-styles": "^8.5.15", + "@fluentui/set-version": "^8.2.14", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@griffel/core": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@griffel/core/-/core-1.15.2.tgz", + "integrity": "sha512-RlsIXoSS3gaYykUgxFpwKAs/DV9cRUKp3CW1kt3iPAtsDTWn/o+8bT1jvBws/tMM2GBu/Uc0EkaIzUPqD7uA+Q==", + "dependencies": { + "@emotion/hash": "^0.9.0", + "@griffel/style-types": "^1.0.3", + "csstype": "^3.1.3", + "rtl-css-js": "^1.16.1", + "stylis": "^4.2.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@griffel/react": { + "version": "1.5.20", + "resolved": "https://registry.npmjs.org/@griffel/react/-/react-1.5.20.tgz", + "integrity": "sha512-1P2yaPctENFSCwyPIYXBmgpNH68c0lc/jwSzPij1QATHDK1AASKuSeq6hW108I67RKjhRyHCcALshdZ3GcQXSg==", + "dependencies": { + "@griffel/core": "^1.15.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@griffel/style-types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@griffel/style-types/-/style-types-1.0.3.tgz", + "integrity": "sha512-AzbbYV/EobNIBtfMtyu2edFin895gjVxtu1nsRhTETUAIb0/LCZoue3Jd/kFLuPwe95rv5WRUBiQpVwJsrrFcw==", + "dependencies": { + "csstype": "^3.1.3" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz", + "integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@microsoft/load-themed-styles": { + "version": "1.10.295", + "resolved": "https://registry.npmjs.org/@microsoft/load-themed-styles/-/load-themed-styles-1.10.295.tgz", + "integrity": "sha512-W+IzEBw8a6LOOfRJM02dTT7BDZijxm+Z7lhtOAz1+y9vQm1Kdz9jlAO+qCEKsfxtUOmKilW8DIRqFw2aUgKeGg==" + }, + "node_modules/@react-spring/animated": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.3.tgz", + "integrity": "sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw==", + "dependencies": { + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.3.tgz", + "integrity": "sha512-IqFdPVf3ZOC1Cx7+M0cXf4odNLxDC+n7IN3MDcVCTIOSBfqEcBebSv+vlY5AhM0zw05PDbjKrNmBpzv/AqpjnQ==", + "dependencies": { + "@react-spring/animated": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/shared": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.3.tgz", + "integrity": "sha512-NEopD+9S5xYyQ0pGtioacLhL2luflh6HACSSDUZOwLHoxA5eku1UPuqcJqjwSD6luKjjLfiLOspxo43FUHKKSA==", + "dependencies": { + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/types": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.3.tgz", + "integrity": "sha512-Kpx/fQ/ZFX31OtlqVEFfgaD1ACzul4NksrvIgYfIFq9JpDHFwQkMVZ10tbo0FU/grje4rcL4EIrjekl3kYwgWw==" + }, + "node_modules/@react-spring/web": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.3.tgz", + "integrity": "sha512-BXt6BpS9aJL/QdVqEIX9YoUy8CE6TJrU0mNCqSoxdXlIeNcEBWOfIyE6B14ENNsyQKS3wOWkiJfco0tCr/9tUg==", + "dependencies": { + "@react-spring/animated": "~9.7.3", + "@react-spring/core": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@remix-run/router": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.2.tgz", + "integrity": "sha512-ACXpdMM9hmKZww21yEqWwiLws/UPLhNKvimN8RrYSqPSvB3ov7sLvAcfvaxePeLvccTQKGdkDIhLYApZVDFuKg==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rollup/plugin-typescript": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.3.tgz", + "integrity": "sha512-8o6cNgN44kQBcpsUJTbTXMTtb87oR1O0zgP3Dxm71hrNgparap3VujgofEilTYJo+ivf2ke6uy3/E5QEaiRlDA==", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0||^3.0.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + }, + "tslib": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.4.tgz", + "integrity": "sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g==", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz", + "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/dompurify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.3.tgz", + "integrity": "sha512-odiGr/9/qMqjcBOe5UhcNLOFHSYmKFOyr+bJ/Xu3Qp4k1pNPAlNLUVNNLcLfjQI7+W7ObX58EdD3H+3p3voOvA==", + "dev": true, + "dependencies": { + "@types/trusted-types": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "node_modules/@types/react": { + "version": "18.2.48", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.48.tgz", + "integrity": "sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.18", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz", + "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", + "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==", + "dev": true + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", + "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.5", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001579", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz", + "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dompurify": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.6.tgz", + "integrity": "sha512-ilkD8YEnnGh1zJ240uJsW7AzE+2qpbOUYjacomn3AvJ6J4JhKGSZ2nh4wUIXPZrEPppaCLx5jFe8T89Rk8tQ7w==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.639", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.639.tgz", + "integrity": "sha512-CkKf3ZUVZchr+zDpAlNLEEy2NJJ9T64ULWaDgy3THXXlPVPkLu3VOs9Bac44nebVtdwl2geSj6AxTtGDOxoXhg==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.11.tgz", + "integrity": "sha512-i8u6mQF0JKJUlGR3OdFLKldJQMMs8OqM9Cc3UCi9XXziJ9WERM5bfkHaEAy0YAvPRMgqSW55W7xYn84XtEFTtA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.11", + "@esbuild/android-arm64": "0.18.11", + "@esbuild/android-x64": "0.18.11", + "@esbuild/darwin-arm64": "0.18.11", + "@esbuild/darwin-x64": "0.18.11", + "@esbuild/freebsd-arm64": "0.18.11", + "@esbuild/freebsd-x64": "0.18.11", + "@esbuild/linux-arm": "0.18.11", + "@esbuild/linux-arm64": "0.18.11", + "@esbuild/linux-ia32": "0.18.11", + "@esbuild/linux-loong64": "0.18.11", + "@esbuild/linux-mips64el": "0.18.11", + "@esbuild/linux-ppc64": "0.18.11", + "@esbuild/linux-riscv64": "0.18.11", + "@esbuild/linux-s390x": "0.18.11", + "@esbuild/linux-x64": "0.18.11", + "@esbuild/netbsd-x64": "0.18.11", + "@esbuild/openbsd-x64": "0.18.11", + "@esbuild/sunos-x64": "0.18.11", + "@esbuild/win32-arm64": "0.18.11", + "@esbuild/win32-ia32": "0.18.11", + "@esbuild/win32-x64": "0.18.11" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyborg": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/keyborg/-/keyborg-2.4.1.tgz", + "integrity": "sha512-B9EZwDd36WKlIq6JmimaTsTDx5E0aUqZcxtgTfK66ut1FbRXYhBmiB7Al2qKzB7CCX9C49sTBiiyVzsXCA6J4Q==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/ndjson-readablestream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ndjson-readablestream/-/ndjson-readablestream-1.0.7.tgz", + "integrity": "sha512-4DDTwYTV4yRnCoXparQTF3JeahTNkLVy7XlA0RHXzAqQ3uU8vcu97bNW8rXAQOKQVJGs2aZoX+7cbvfs0LENEA==" + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-dom/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.21.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.21.3.tgz", + "integrity": "sha512-a0H638ZXULv1OdkmiK6s6itNhoy33ywxmUFT/xtSoVyf9VnC7n7+VT4LjVzdIHSaF5TIh9ylUgxMXksHTgGrKg==", + "dependencies": { + "@remix-run/router": "1.14.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.21.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.21.3.tgz", + "integrity": "sha512-kNzubk7n4YHSrErzjLK72j0B5i969GsuCGazRl3G6j1zqZBLjuSlYBdVdkDOgzGdPIffUOc9nmgiadTEVoq91g==", + "dependencies": { + "@remix-run/router": "1.14.2", + "react-router": "6.21.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/resolve": { + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rtl-css-js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", + "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==", + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, + "node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stylis": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", + "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==" + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tabster": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/tabster/-/tabster-5.2.0.tgz", + "integrity": "sha512-cSi3a0gGeM9Co/gTKHlhTFfiitwVjcA+kP9lJux0U7QaRrZox1yYrfbwZhJXM7N0fux7BgvCYaOxME5k0EQ0tA==", + "dependencies": { + "keyborg": "^2.2.0", + "tslib": "^2.3.1" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/use-disposable": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/use-disposable/-/use-disposable-1.0.2.tgz", + "integrity": "sha512-UMaXVlV77dWOu4GqAFNjRzHzowYKUKbJBQfCexvahrYeIz4OkUYUjna4Tjjdf92NH8Nm8J7wEfFRgTIwYjO5jg==", + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/vite": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", + "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", + "dev": true, + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@azure/msal-browser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.2.0.tgz", + "integrity": "sha512-le2qutddMiq0i3ErQaLKuwP1DpNgdd9iXPs3fSCsLuBrdGg9B4/j4ArCAHCwgxA82Ydj9BcqtMIL5BSWwU+P5A==", + "requires": { + "@azure/msal-common": "14.1.0" + } + }, + "@azure/msal-common": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.1.0.tgz", + "integrity": "sha512-xphmhcfl5VL+uq5//VKMwQn+wfEZLMKNpFCcMi8Ur8ej5UT166g6chBsxgMzc9xo9Y24R9FB3m/tjDiV03xMIA==" + }, + "@azure/msal-react": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@azure/msal-react/-/msal-react-2.0.4.tgz", + "integrity": "sha512-BujRm5FBDWYXyr3pnmubS4dIqZMlurYVtV2AyztoeAFUd+nh3XQZD9knHBqTyu53IDjhCCvUPUke/jSkv5WGlg==", + "requires": { + "@rollup/plugin-typescript": "^11.1.0", + "rollup": "^3.20.2" + } + }, + "@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + } + }, + "@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true + }, + "@babel/core": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", + "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6", + "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": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "requires": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz", + "integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" + } + }, + "@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "dev": true + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", + "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", + "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/runtime": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", + "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/traverse": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", + "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "@esbuild/android-arm": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.11.tgz", + "integrity": "sha512-q4qlUf5ucwbUJZXF5tEQ8LF7y0Nk4P58hOsGk3ucY0oCwgQqAnqXVbUuahCddVHfrxmpyewRpiTHwVHIETYu7Q==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.11.tgz", + "integrity": "sha512-snieiq75Z1z5LJX9cduSAjUr7vEI1OdlzFPMw0HH5YI7qQHDd3qs+WZoMrWYDsfRJSq36lIA6mfZBkvL46KoIw==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.11.tgz", + "integrity": "sha512-iPuoxQEV34+hTF6FT7om+Qwziv1U519lEOvekXO9zaMMlT9+XneAhKL32DW3H7okrCOBQ44BMihE8dclbZtTuw==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.11.tgz", + "integrity": "sha512-Gm0QkI3k402OpfMKyQEEMG0RuW2LQsSmI6OeO4El2ojJMoF5NLYb3qMIjvbG/lbMeLOGiW6ooU8xqc+S0fgz2w==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.11.tgz", + "integrity": "sha512-N15Vzy0YNHu6cfyDOjiyfJlRJCB/ngKOAvoBf1qybG3eOq0SL2Lutzz9N7DYUbb7Q23XtHPn6lMDF6uWbGv9Fw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.11.tgz", + "integrity": "sha512-atEyuq6a3omEY5qAh5jIORWk8MzFnCpSTUruBgeyN9jZq1K/QI9uke0ATi3MHu4L8c59CnIi4+1jDKMuqmR71A==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.11.tgz", + "integrity": "sha512-XtuPrEfBj/YYYnAAB7KcorzzpGTvOr/dTtXPGesRfmflqhA4LMF0Gh/n5+a9JBzPuJ+CGk17CA++Hmr1F/gI0Q==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.11.tgz", + "integrity": "sha512-Idipz+Taso/toi2ETugShXjQ3S59b6m62KmLHkJlSq/cBejixmIydqrtM2XTvNCywFl3VC7SreSf6NV0i6sRyg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.11.tgz", + "integrity": "sha512-c6Vh2WS9VFKxKZ2TvJdA7gdy0n6eSy+yunBvv4aqNCEhSWVor1TU43wNRp2YLO9Vng2G+W94aRz+ILDSwAiYog==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.11.tgz", + "integrity": "sha512-S3hkIF6KUqRh9n1Q0dSyYcWmcVa9Cg+mSoZEfFuzoYXXsk6196qndrM+ZiHNwpZKi3XOXpShZZ+9dfN5ykqjjw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.11.tgz", + "integrity": "sha512-MRESANOoObQINBA+RMZW+Z0TJWpibtE7cPFnahzyQHDCA9X9LOmGh68MVimZlM9J8n5Ia8lU773te6O3ILW8kw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.11.tgz", + "integrity": "sha512-qVyPIZrXNMOLYegtD1u8EBccCrBVshxMrn5MkuFc3mEVsw7CCQHaqZ4jm9hbn4gWY95XFnb7i4SsT3eflxZsUg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.11.tgz", + "integrity": "sha512-T3yd8vJXfPirZaUOoA9D2ZjxZX4Gr3QuC3GztBJA6PklLotc/7sXTOuuRkhE9W/5JvJP/K9b99ayPNAD+R+4qQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.11.tgz", + "integrity": "sha512-evUoRPWiwuFk++snjH9e2cAjF5VVSTj+Dnf+rkO/Q20tRqv+644279TZlPK8nUGunjPAtQRCj1jQkDAvL6rm2w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.11.tgz", + "integrity": "sha512-/SlRJ15XR6i93gRWquRxYCfhTeC5PdqEapKoLbX63PLCmAkXZHY2uQm2l9bN0oPHBsOw2IswRZctMYS0MijFcg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.11.tgz", + "integrity": "sha512-xcncej+wF16WEmIwPtCHi0qmx1FweBqgsRtEL1mSHLFR6/mb3GEZfLQnx+pUDfRDEM4DQF8dpXIW7eDOZl1IbA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.11.tgz", + "integrity": "sha512-aSjMHj/F7BuS1CptSXNg6S3M4F3bLp5wfFPIJM+Km2NfIVfFKhdmfHF9frhiCLIGVzDziggqWll0B+9AUbud/Q==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.11.tgz", + "integrity": "sha512-tNBq+6XIBZtht0xJGv7IBB5XaSyvYPCm1PxJ33zLQONdZoLVM0bgGqUrXnJyiEguD9LU4AHiu+GCXy/Hm9LsdQ==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.11.tgz", + "integrity": "sha512-kxfbDOrH4dHuAAOhr7D7EqaYf+W45LsAOOhAet99EyuxxQmjbk8M9N4ezHcEiCYPaiW8Dj3K26Z2V17Gt6p3ng==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.11.tgz", + "integrity": "sha512-Sh0dDRyk1Xi348idbal7lZyfSkjhJsdFeuC13zqdipsvMetlGiFQNdO+Yfp6f6B4FbyQm7qsk16yaZk25LChzg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.11.tgz", + "integrity": "sha512-o9JUIKF1j0rqJTFbIoF4bXj6rvrTZYOrfRcGyL0Vm5uJ/j5CkBD/51tpdxe9lXEDouhRgdr/BYzUrDOvrWwJpg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.11.tgz", + "integrity": "sha512-rQI4cjLHd2hGsM1LqgDI7oOCYbQ6IBOVsX9ejuRMSze0GqXUG2ekwiKkiBU1pRGSeCqFFHxTrcEydB2Hyoz9CA==", + "dev": true, + "optional": true + }, + "@floating-ui/core": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.3.tgz", + "integrity": "sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==", + "requires": { + "@floating-ui/utils": "^0.2.0" + } + }, + "@floating-ui/devtools": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/devtools/-/devtools-0.2.1.tgz", + "integrity": "sha512-8PHJLbD6VhBh+LJ1uty/Bz30qs02NXCE5u8WpOhSewlYXUWl03GNXknr9AS2yaAWJEQaY27x7eByJs44gODBcw==", + "requires": {} + }, + "@floating-ui/dom": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.4.tgz", + "integrity": "sha512-jByEsHIY+eEdCjnTVu+E3ephzTOzkQ8hgUfGwos+bg7NlH33Zc5uO+QHz1mrQUOgIKKDD1RtS201P9NvAfq3XQ==", + "requires": { + "@floating-ui/core": "^1.5.3", + "@floating-ui/utils": "^0.2.0" + } + }, + "@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, + "@fluentui/date-time-utilities": { + "version": "8.5.16", + "resolved": "https://registry.npmjs.org/@fluentui/date-time-utilities/-/date-time-utilities-8.5.16.tgz", + "integrity": "sha512-l+mLfJ2VhdHjBpELLLPDaWgT7GMLynm2aqR7SttbEb6Jh7hc/7ck1MWm93RTb3gYVHYai8SENqimNcvIxHt/zg==", + "requires": { + "@fluentui/set-version": "^8.2.14", + "tslib": "^2.1.0" + } + }, + "@fluentui/dom-utilities": { + "version": "2.2.14", + "resolved": "https://registry.npmjs.org/@fluentui/dom-utilities/-/dom-utilities-2.2.14.tgz", + "integrity": "sha512-+4DVm5sNfJh+l8fM+7ylpOkGNZkNr4X1z1uKQPzRJ1PRhlnvc6vLpWNNicGwpjTbgufSrVtGKXwP5sf++r81lg==", + "requires": { + "@fluentui/set-version": "^8.2.14", + "tslib": "^2.1.0" + } + }, + "@fluentui/font-icons-mdl2": { + "version": "8.5.31", + "resolved": "https://registry.npmjs.org/@fluentui/font-icons-mdl2/-/font-icons-mdl2-8.5.31.tgz", + "integrity": "sha512-jioHZ9XUfR9vUT5XnxdCrJ+hoC9TpYim+4YdtlUE/euI8kdW1tDZ5zqlSNk1GLDR34n03R09yWj5gVDCcMJbyQ==", + "requires": { + "@fluentui/set-version": "^8.2.14", + "@fluentui/style-utilities": "^8.10.2", + "@fluentui/utilities": "^8.13.24", + "tslib": "^2.1.0" + } + }, + "@fluentui/foundation-legacy": { + "version": "8.2.51", + "resolved": "https://registry.npmjs.org/@fluentui/foundation-legacy/-/foundation-legacy-8.2.51.tgz", + "integrity": "sha512-z/jrp1imV66/D2MGpN/55LGk/Istymk5tN+XUFHDENDi+9zyb2MgSxFshp774DJIrg3vVlyuS8oo+dBuTM3UbQ==", + "requires": { + "@fluentui/merge-styles": "^8.5.15", + "@fluentui/set-version": "^8.2.14", + "@fluentui/style-utilities": "^8.10.2", + "@fluentui/utilities": "^8.13.24", + "tslib": "^2.1.0" + } + }, + "@fluentui/keyboard-key": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@fluentui/keyboard-key/-/keyboard-key-0.4.14.tgz", + "integrity": "sha512-XzZHcyFEM20H23h3i15UpkHi2AhRBriXPGAHq0Jm98TKFppXehedjjEFuUsh+CyU5JKBhDalWp8TAQ1ArpNzow==", + "requires": { + "tslib": "^2.1.0" + } + }, + "@fluentui/keyboard-keys": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@fluentui/keyboard-keys/-/keyboard-keys-9.0.7.tgz", + "integrity": "sha512-vaQ+lOveQTdoXJYqDQXWb30udSfTVcIuKk1rV0X0eGAgcHeSDeP1HxMy+OgHOQZH3OiBH4ZYeWxb+tmfiDiygQ==", + "requires": { + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/merge-styles": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/@fluentui/merge-styles/-/merge-styles-8.5.15.tgz", + "integrity": "sha512-4CdKwo4k1Un2QLulpSVIz/KMgLNBMgin4NPyapmKDMVuO1OOxJUqfocubRGNO5x9mKgAMMYwBKGO9i0uxMMpJw==", + "requires": { + "@fluentui/set-version": "^8.2.14", + "tslib": "^2.1.0" + } + }, + "@fluentui/priority-overflow": { + "version": "9.1.11", + "resolved": "https://registry.npmjs.org/@fluentui/priority-overflow/-/priority-overflow-9.1.11.tgz", + "integrity": "sha512-sdrpavvKX2kepQ1d6IaI3ObLq5SAQBPRHPGx2+wiMWL7cEx9vGGM0fmeicl3soqqmM5uwCmWnZk9QZv9XOY98w==", + "requires": { + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react": { + "version": "8.114.4", + "resolved": "https://registry.npmjs.org/@fluentui/react/-/react-8.114.4.tgz", + "integrity": "sha512-dVpfFSpWUxdyqWlCVSXX5d34S760h4MaQjGR2/TPavtcJRRpJDHbBN2Hn7s4riA6YX5N7bTdN372UvIVbBbzuw==", + "requires": { + "@fluentui/date-time-utilities": "^8.5.16", + "@fluentui/font-icons-mdl2": "^8.5.31", + "@fluentui/foundation-legacy": "^8.2.51", + "@fluentui/merge-styles": "^8.5.15", + "@fluentui/react-focus": "^8.8.38", + "@fluentui/react-hooks": "^8.6.36", + "@fluentui/react-portal-compat-context": "^9.0.11", + "@fluentui/react-window-provider": "^2.2.18", + "@fluentui/set-version": "^8.2.14", + "@fluentui/style-utilities": "^8.10.2", + "@fluentui/theme": "^2.6.41", + "@fluentui/utilities": "^8.13.24", + "@microsoft/load-themed-styles": "^1.10.26", + "tslib": "^2.1.0" + } + }, + "@fluentui/react-accordion": { + "version": "9.3.38", + "resolved": "https://registry.npmjs.org/@fluentui/react-accordion/-/react-accordion-9.3.38.tgz", + "integrity": "sha512-BB8d9+Jr0v4SW58OJTIyvsxhA/iOBbvIkQZlVHKqt4tL8dHOIFPrApw5WqQqaSYJsEwt4HxmlNU4Dv8qRughbg==", + "requires": { + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-alert": { + "version": "9.0.0-beta.104", + "resolved": "https://registry.npmjs.org/@fluentui/react-alert/-/react-alert-9.0.0-beta.104.tgz", + "integrity": "sha512-Z8BGSyzEKok5wlJF2cUc8GUj2q+c1D+119YF0WtHLiieh7pwOHjBcDJOHqnaVnQNbhetIA3NUht2z0e1wgOK5w==", + "requires": { + "@fluentui/react-avatar": "^9.6.9", + "@fluentui/react-button": "^9.3.65", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-aria": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@fluentui/react-aria/-/react-aria-9.7.3.tgz", + "integrity": "sha512-YwyPNEcBDCdY6YzhrIrtlSrLs2Le7X1jLq9em8OnqHeiO22dBmg5xlBJoAMwJ8awCpI9xhu1PhU/2VJY4YqNuA==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-utilities": "^9.16.1", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-avatar": { + "version": "9.6.9", + "resolved": "https://registry.npmjs.org/@fluentui/react-avatar/-/react-avatar-9.6.9.tgz", + "integrity": "sha512-3aZeUhGOg+UlHsp2x//G4VKRWKclcsZvX6L9UVnHsA/nQqRw7C5Bfo9iFNsEeJ3R5W5mFA6LyEFWedJ7QdAmdQ==", + "requires": { + "@fluentui/react-badge": "^9.2.22", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-popover": "^9.8.33", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-tooltip": "^9.4.11", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-badge": { + "version": "9.2.22", + "resolved": "https://registry.npmjs.org/@fluentui/react-badge/-/react-badge-9.2.22.tgz", + "integrity": "sha512-zzimP5mZiiCOm8expUTzD6yvvKbnKq22PK/L6+oNpifrvQnDwJF/0nwXQVjA3+icNoYTaHe/q0fFivpXV+Js6g==", + "requires": { + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-breadcrumb": { + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/@fluentui/react-breadcrumb/-/react-breadcrumb-9.0.11.tgz", + "integrity": "sha512-L+AQqZz1gqkScD8IW1CjZWGNrDaHDc/gSv+PrvgSZeGDPibGj6TnLygJ7BKM+rQ+Hc2SbCogKbERpQZCbrSFvA==", + "requires": { + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-button": "^9.3.65", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-link": "^9.2.7", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-button": { + "version": "9.3.65", + "resolved": "https://registry.npmjs.org/@fluentui/react-button/-/react-button-9.3.65.tgz", + "integrity": "sha512-3VOt29AugkfR7VMnkKON449E7Sn/nvc6BBT4kJDGKQY+Nm5d2p9e4HmHp1UaM9zRPt47lagTY2WFJNrKKSe/BA==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-card": { + "version": "9.0.64", + "resolved": "https://registry.npmjs.org/@fluentui/react-card/-/react-card-9.0.64.tgz", + "integrity": "sha512-TB/Zk+tLDUPNyAd2y8BvN0T2nroimtBOpB5GTK72E5sWPk0kaKIHwBEfXxNFGdGXcw0TAmVNqYi4ks37vh0Rgg==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-checkbox": { + "version": "9.2.8", + "resolved": "https://registry.npmjs.org/@fluentui/react-checkbox/-/react-checkbox-9.2.8.tgz", + "integrity": "sha512-L4aWzeZdi98d0ZhgNPtxghfhasQv1qlxIRMaPxtwvk5TN6i9YmRF8vf5Pmf0PESjT+zp3VPcisHcIfcqG26SmQ==", + "requires": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-combobox": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-combobox/-/react-combobox-9.7.0.tgz", + "integrity": "sha512-YmTdg04rvsg2+Dkw3ob+YLnS9rm3TLVMMNYTH0T64/FM3qirHntIXGbhMZXP5Cdo14gzQwr/e78NjBRKfYO4Wg==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-positioning": "^9.12.4", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-components": { + "version": "9.45.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-components/-/react-components-9.45.0.tgz", + "integrity": "sha512-Y+Laj1dvRcCp/nWT0DExRXoh7oKTX458g6oltrGjhIHikq4D6/kssK5tfhCyknPLwIlVSYi5J+G6L3NfvI8a8w==", + "requires": { + "@fluentui/react-accordion": "^9.3.38", + "@fluentui/react-alert": "9.0.0-beta.104", + "@fluentui/react-avatar": "^9.6.9", + "@fluentui/react-badge": "^9.2.22", + "@fluentui/react-breadcrumb": "^9.0.11", + "@fluentui/react-button": "^9.3.65", + "@fluentui/react-card": "^9.0.64", + "@fluentui/react-checkbox": "^9.2.8", + "@fluentui/react-combobox": "^9.7.0", + "@fluentui/react-dialog": "^9.9.7", + "@fluentui/react-divider": "^9.2.58", + "@fluentui/react-drawer": "^9.1.1", + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-image": "^9.1.55", + "@fluentui/react-infobutton": "9.0.0-beta.88", + "@fluentui/react-infolabel": "^9.0.16", + "@fluentui/react-input": "^9.4.60", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-link": "^9.2.7", + "@fluentui/react-menu": "^9.12.45", + "@fluentui/react-message-bar": "^9.0.16", + "@fluentui/react-overflow": "^9.1.8", + "@fluentui/react-persona": "^9.2.68", + "@fluentui/react-popover": "^9.8.33", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-positioning": "^9.12.4", + "@fluentui/react-progress": "^9.1.60", + "@fluentui/react-provider": "^9.13.8", + "@fluentui/react-radio": "^9.2.3", + "@fluentui/react-select": "^9.1.60", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-skeleton": "^9.0.48", + "@fluentui/react-slider": "^9.1.65", + "@fluentui/react-spinbutton": "^9.2.60", + "@fluentui/react-spinner": "^9.3.38", + "@fluentui/react-switch": "^9.1.65", + "@fluentui/react-table": "^9.11.5", + "@fluentui/react-tabs": "^9.4.6", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-tags": "^9.0.22", + "@fluentui/react-text": "^9.4.7", + "@fluentui/react-textarea": "^9.3.60", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-toast": "^9.3.27", + "@fluentui/react-toolbar": "^9.1.66", + "@fluentui/react-tooltip": "^9.4.11", + "@fluentui/react-tree": "^9.4.25", + "@fluentui/react-utilities": "^9.16.1", + "@fluentui/react-virtualizer": "9.0.0-alpha.66", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-context-selector": { + "version": "9.1.49", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.49.tgz", + "integrity": "sha512-u4wRNfnyfuZDalVEESBPFQ0Ue4yYu+ozkPQvuEV6kriQGnAQQyyVbIidOCuP7Sja0nBwgM8eAzK0uX/slmmj3Q==", + "requires": { + "@fluentui/react-utilities": "^9.16.1", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-dialog": { + "version": "9.9.7", + "resolved": "https://registry.npmjs.org/@fluentui/react-dialog/-/react-dialog-9.9.7.tgz", + "integrity": "sha512-5/6MeaHOYpx8Vt0auMJGLCjn6O1IYtl6IhwdwRNXL6AS1o4F24IKXdWZPtiHWuvzbuZAQd3+5nRDUE5KC9We6A==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "react-transition-group": "^4.4.1" + } + }, + "@fluentui/react-divider": { + "version": "9.2.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-divider/-/react-divider-9.2.58.tgz", + "integrity": "sha512-y1ECy1zM4imKhpyOyUGugB+J30tfySO5hhrsIcpaiUQxRjE4IhZf2ZG6EqAQYLinJ+hV06yLZoazekljlvk6yw==", + "requires": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-drawer": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-drawer/-/react-drawer-9.1.1.tgz", + "integrity": "sha512-3zvbbeaLLJZa4MXRpW8Ta4DFZ5457Tq9/4a0CqsIW/+8EuwtJwO+FB5a0DS6j0q6kN4mjkWF19OvzMkJsSTRVw==", + "requires": { + "@fluentui/react-dialog": "^9.9.7", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-motion-preview": "^0.5.10", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-field": { + "version": "9.1.50", + "resolved": "https://registry.npmjs.org/@fluentui/react-field/-/react-field-9.1.50.tgz", + "integrity": "sha512-2mbx7YReMWvrgi3set9KepLLgMyNJ7StLu/HiHMM3jkcgPt3mGfwoJEsEKt+xd8eUAo4b82F7t+tHI4f9yzJaQ==", + "requires": { + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-focus": { + "version": "8.8.38", + "resolved": "https://registry.npmjs.org/@fluentui/react-focus/-/react-focus-8.8.38.tgz", + "integrity": "sha512-vnsaY7hJSPIJBxm5Pj0FrcFDumV6kKgFVpsKsEKJzb1D88rDDLcmvz9jWUx68a3ru6idEbZYmyePGT1IiRsAug==", + "requires": { + "@fluentui/keyboard-key": "^0.4.14", + "@fluentui/merge-styles": "^8.5.15", + "@fluentui/set-version": "^8.2.14", + "@fluentui/style-utilities": "^8.10.2", + "@fluentui/utilities": "^8.13.24", + "tslib": "^2.1.0" + } + }, + "@fluentui/react-hooks": { + "version": "8.6.36", + "resolved": "https://registry.npmjs.org/@fluentui/react-hooks/-/react-hooks-8.6.36.tgz", + "integrity": "sha512-kI0Z4Q4xHUs4SOmmI5n5OH5fPckqMSCovTRpiuxzCO2TNzLmfC861+nqf4Ygw/ChqNm2gWNZZfUADfnNAEsq+Q==", + "requires": { + "@fluentui/react-window-provider": "^2.2.18", + "@fluentui/set-version": "^8.2.14", + "@fluentui/utilities": "^8.13.24", + "tslib": "^2.1.0" + } + }, + "@fluentui/react-icons": { + "version": "2.0.225", + "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.225.tgz", + "integrity": "sha512-L9phN3bAMlZCa5+/ObGjIO+5GI8M50ym766sraSq92jaJwgAXrCJDLWuDGWZRGrC63DcagtR2culptj3q7gMMg==", + "requires": { + "@griffel/react": "^1.0.0", + "tslib": "^2.1.0" + } + }, + "@fluentui/react-image": { + "version": "9.1.55", + "resolved": "https://registry.npmjs.org/@fluentui/react-image/-/react-image-9.1.55.tgz", + "integrity": "sha512-hYP61OWLuGSJNPOGJXtphbiDESfLB+/vsODKQsJhrDRJ2CSNMAfNznPHucqGRRN6AWQOI/BynJDS5F22Y//7CQ==", + "requires": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-infobutton": { + "version": "9.0.0-beta.88", + "resolved": "https://registry.npmjs.org/@fluentui/react-infobutton/-/react-infobutton-9.0.0-beta.88.tgz", + "integrity": "sha512-NVZyfrLtoFNu7cGkp2ORWsxJiCk1JgN4CVBDj03QSIh14EsPMwphYgDwfQ8TZOF2Nub0DGtC7/tF8IUlb/aP6g==", + "requires": { + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-popover": "^9.8.33", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-infolabel": { + "version": "9.0.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-infolabel/-/react-infolabel-9.0.16.tgz", + "integrity": "sha512-UCY+2vB4vOn0LfVhbgkyNG0EiuKIe0PdxEAtLU2PqosHLkaLKnYDKJdiIS/oaFmyNtGHmMxRkigvZpZ7h74f9g==", + "requires": { + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-popover": "^9.8.33", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-input": { + "version": "9.4.60", + "resolved": "https://registry.npmjs.org/@fluentui/react-input/-/react-input-9.4.60.tgz", + "integrity": "sha512-kuk24K0X0gckTCssXoiWvZsTFVpZJv+WPl2fkjxeffzmFfBZtJUFQkXeC4/hcAg+aScjZnEtqjHjwDEbjZqkeA==", + "requires": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-jsx-runtime": { + "version": "9.0.27", + "resolved": "https://registry.npmjs.org/@fluentui/react-jsx-runtime/-/react-jsx-runtime-9.0.27.tgz", + "integrity": "sha512-9wxsWxVI7RLXsdK+7lzp7TK0FJKnrrj+Igxn0prqAvXdBRiFcuycoCJaHzC4Ka+Hsiol8NQg6xaIR59a28lmyQ==", + "requires": { + "@fluentui/react-utilities": "^9.16.1", + "@swc/helpers": "^0.5.1", + "react-is": "^17.0.2" + } + }, + "@fluentui/react-label": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-label/-/react-label-9.1.58.tgz", + "integrity": "sha512-0ouSMop4vpXJzMvAyfmIr3TgDM/W1k+GFm8ZPD5fDQCopSJ+h3kvUZg5pqaXpBwamvZ16+qRARfTNITp2U7Rjw==", + "requires": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-link": { + "version": "9.2.7", + "resolved": "https://registry.npmjs.org/@fluentui/react-link/-/react-link-9.2.7.tgz", + "integrity": "sha512-z4X9dcUc/7FlqDxbGKbOfWubru+QimtzgMtlVxZ30pkC959hfIbFpbBY6Me76UOuFiOZxUPdfyY/73ekhhhVxw==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-menu": { + "version": "9.12.45", + "resolved": "https://registry.npmjs.org/@fluentui/react-menu/-/react-menu-9.12.45.tgz", + "integrity": "sha512-qhpmuvAB4DUmmC5lNMakVvZjTdj/GZnH6WctNGZp94iCZLhcnIQcM9l0PvRpUpU1v3irXRyE5QV+x+wXC0awTw==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-positioning": "^9.12.4", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-message-bar": { + "version": "9.0.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-message-bar/-/react-message-bar-9.0.16.tgz", + "integrity": "sha512-R1VnqcFwu0pM2Yk8rjkN48Lx/n44UFD13BuY8/JeEuU8XQ8hLnEBVtdHjzRPJk+iM5in2ScMMQj4Z0nWyCRM1Q==", + "requires": { + "@fluentui/react-button": "^9.3.65", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "react-transition-group": "^4.4.1" + } + }, + "@fluentui/react-motion-preview": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@fluentui/react-motion-preview/-/react-motion-preview-0.5.10.tgz", + "integrity": "sha512-6iwF3N4hB6IxCoFVusgA2mp6mrTknwcsVGNYEQw1YF5WgGOMF3M0N1xNpN61/SYziT6HSUaI38NaA7LI3Dp3Sw==", + "requires": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-overflow": { + "version": "9.1.8", + "resolved": "https://registry.npmjs.org/@fluentui/react-overflow/-/react-overflow-9.1.8.tgz", + "integrity": "sha512-W8L68+0bUtfGr72LRx+U05EZLO0E8VMfscDiNKiEjDrOqdBnqNAIDN86825wrN77HH2wvILN07EhPOauqzz8YQ==", + "requires": { + "@fluentui/priority-overflow": "^9.1.11", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-persona": { + "version": "9.2.68", + "resolved": "https://registry.npmjs.org/@fluentui/react-persona/-/react-persona-9.2.68.tgz", + "integrity": "sha512-CYtDiZ34GGaw7lZ85uHZOuYXzkY21VHN6cUlGY1TJn98+Xz+y7JoVLIG7KZHHp2JzmmjtwjvgnqAdOun5LrWig==", + "requires": { + "@fluentui/react-avatar": "^9.6.9", + "@fluentui/react-badge": "^9.2.22", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-popover": { + "version": "9.8.33", + "resolved": "https://registry.npmjs.org/@fluentui/react-popover/-/react-popover-9.8.33.tgz", + "integrity": "sha512-0yPX6KCdMEGmrvJnQles5iTKN0OZ2vNSPVdkbyEKIUKj5DrNK1cMZEV/7Tgrtn922fx3/74FLMqEpEDTdrvQ/Q==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-positioning": "^9.12.4", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-portal": { + "version": "9.4.10", + "resolved": "https://registry.npmjs.org/@fluentui/react-portal/-/react-portal-9.4.10.tgz", + "integrity": "sha512-k8fTRv9wTPSPCuNBFE2HxIhXsVYoG6Azb6Ib2xaDK+nczoW2WbsmNmwBJGEGi8UKjIoQzV+95KsYQ9me+uqKPA==", + "requires": { + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "use-disposable": "^1.0.1" + } + }, + "@fluentui/react-portal-compat-context": { + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/@fluentui/react-portal-compat-context/-/react-portal-compat-context-9.0.11.tgz", + "integrity": "sha512-ubvW/ej0O+Pago9GH3mPaxzUgsNnBoqvghNamWjyKvZIViyaXUG6+sgcAl721R+qGAFac+A20akI5qDJz/xtdg==", + "requires": { + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-positioning": { + "version": "9.12.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-positioning/-/react-positioning-9.12.4.tgz", + "integrity": "sha512-qQAjHF/FJFs2TyK0x08t0iFtDQlGNGH0OFC3jrG1xIFEe3nFPoeYeNT3zxOmj+D7bvlcJTIITcoe++YQTnCf4w==", + "requires": { + "@floating-ui/devtools": "0.2.1", + "@floating-ui/dom": "^1.2.0", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-progress": { + "version": "9.1.60", + "resolved": "https://registry.npmjs.org/@fluentui/react-progress/-/react-progress-9.1.60.tgz", + "integrity": "sha512-9wC7lWdo3S8rhxKWlIhcYAzsZNw+rL2HvNJTvEvFxXcOG7nJxP/3mGclV/jCCwDoPDnt9BT+40pGK84eD0BNIA==", + "requires": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-provider": { + "version": "9.13.8", + "resolved": "https://registry.npmjs.org/@fluentui/react-provider/-/react-provider-9.13.8.tgz", + "integrity": "sha512-FCvDMjs/BNAcqJuHU+kN/lqLB2RDQ/LQo29ltfLKFlTR1nTUNJvPMOVhjj6eEt+t81628LOYhbbaXOj9rYtfGg==", + "requires": { + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/core": "^1.14.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-radio": { + "version": "9.2.3", + "resolved": "https://registry.npmjs.org/@fluentui/react-radio/-/react-radio-9.2.3.tgz", + "integrity": "sha512-8eKeUL0ZNr792Q6NGWPp7dpOV2IFcjAQ2oWR2/bruQVu8LMzYYKe2o6pQWdCag6UGPZuszkms9Xl7zPdDQBUdA==", + "requires": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-select": { + "version": "9.1.60", + "resolved": "https://registry.npmjs.org/@fluentui/react-select/-/react-select-9.1.60.tgz", + "integrity": "sha512-4HfRRTlGStOgtO00RY6jmOwz6MXnoa9gtjkV7StLmJZ2U5NTjVUrnp2dP1Vjb6hO13xaihWGEYyYKnsQ3R7kIw==", + "requires": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-shared-contexts": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-shared-contexts/-/react-shared-contexts-9.14.0.tgz", + "integrity": "sha512-P9yhg31WYfB1W66/gD3+qVCLBsyIEcOzQvKVaIQvd9UhF67lNW4kMXUB6YVOk5PV0Og4hXnkH/vuHl7YMD9RHw==", + "requires": { + "@fluentui/react-theme": "^9.1.16", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-skeleton": { + "version": "9.0.48", + "resolved": "https://registry.npmjs.org/@fluentui/react-skeleton/-/react-skeleton-9.0.48.tgz", + "integrity": "sha512-P0Rw5hIOn5CrZIWg7nVoK3gamxFhZI80KcRVaWap4O3gLo5C8nKHJWOtyBQZ5WKH+S6hoEGZ2USL6CoyXslxeQ==", + "requires": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-slider": { + "version": "9.1.65", + "resolved": "https://registry.npmjs.org/@fluentui/react-slider/-/react-slider-9.1.65.tgz", + "integrity": "sha512-7kuJMIojxCmNOuiRmQwh9iiXx8zwxkrgvsWmReRIBX0WB6w1VqMcuuikq2Z2ISgNPmepCX8W+qDfx8Ne4F/HtQ==", + "requires": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-spinbutton": { + "version": "9.2.60", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinbutton/-/react-spinbutton-9.2.60.tgz", + "integrity": "sha512-0IIxEH0CTf4fNMoyvMa37bc63+0ZlznlsNy8lF3hujAT8Z9sUKVMH68e6tGUuXGJIkCUyDKU8HA+9FF2DyPvNA==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-spinner": { + "version": "9.3.38", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinner/-/react-spinner-9.3.38.tgz", + "integrity": "sha512-dPJr7/rgU2Qe/K2BciJTAEwEd0ytGpCw3VOVyK2T25w7Jw5RAHmgP+mbw+7se44Mr6sd1LH76mh5sfmQ3tODgw==", + "requires": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-switch": { + "version": "9.1.65", + "resolved": "https://registry.npmjs.org/@fluentui/react-switch/-/react-switch-9.1.65.tgz", + "integrity": "sha512-P0DwogD6hZJ3O005zCFPDoFXuzkrpKMrAeQGh9X0fqFP5JyHXVCgAAZQOLcphbbT9QukoEF5irN2Z4L9gBn57A==", + "requires": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-label": "^9.1.58", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-table": { + "version": "9.11.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-table/-/react-table-9.11.5.tgz", + "integrity": "sha512-roQRITOtl1aqXlachS2oTraVE45x3KdDrX0KyQGCdcQRxNprXJW6dIK9QjlbAL6yAsAMDafmFA4y9uRxl408dQ==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-avatar": "^9.6.9", + "@fluentui/react-checkbox": "^9.2.8", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-radio": "^9.2.3", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-tabs": { + "version": "9.4.6", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabs/-/react-tabs-9.4.6.tgz", + "integrity": "sha512-LQvibLeJFyqKKiOjZUkRvbfLtsVosUhNUdh1SCQUPxQVpEPSK6XgwK0A1+jjoVhKn+PAJakxRINgnvqQD8pQBA==", + "requires": { + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-tabster": { + "version": "9.17.3", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabster/-/react-tabster-9.17.3.tgz", + "integrity": "sha512-cFcUYrkGW15w5yXzCPTTVG/7x5kNXxnhQXuh8SPyCc9JZeG7XI3+hy1T37PsXGxNS4KN9ePHkBHzgDfYO4gzYQ==", + "requires": { + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "keyborg": "^2.3.0", + "tabster": "^5.0.1" + } + }, + "@fluentui/react-tags": { + "version": "9.0.22", + "resolved": "https://registry.npmjs.org/@fluentui/react-tags/-/react-tags-9.0.22.tgz", + "integrity": "sha512-gQIOCVu3HIfGjtAmwOnwBEnTsNyRBU8Pvs6EugpUyyqkRjzbm5TnL3LtiUy4f6/+NuaRqcYAvhwpdUhrlciwcA==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-avatar": "^9.6.9", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-text": { + "version": "9.4.7", + "resolved": "https://registry.npmjs.org/@fluentui/react-text/-/react-text-9.4.7.tgz", + "integrity": "sha512-c6uJ98B35L8sviYxhQj1i+LW+HVNDdco2ImS9VLv/Duo4HiYs1G2y1YhtBDDiGxLe2moIvfg9ajDzMZV29aXFw==", + "requires": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-textarea": { + "version": "9.3.60", + "resolved": "https://registry.npmjs.org/@fluentui/react-textarea/-/react-textarea-9.3.60.tgz", + "integrity": "sha512-wH4MBWT4EOgNH9FXTjcgH34oANUaoduhmVjffnxaPl3R767Ak0fZPG7kky7yrLMjTDUSwILsEj/q+hsN6o+7Ag==", + "requires": { + "@fluentui/react-field": "^9.1.50", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-theme": { + "version": "9.1.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-theme/-/react-theme-9.1.16.tgz", + "integrity": "sha512-QK2dGE5aQXN1UGdiEmGKpYGP3tHXIchLvFf8DEEOWnF4XBc9SiEPNFYkvLMJjHxZmDz4D670rsOPe0r5jFDEKQ==", + "requires": { + "@fluentui/tokens": "1.0.0-alpha.13", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-toast": { + "version": "9.3.27", + "resolved": "https://registry.npmjs.org/@fluentui/react-toast/-/react-toast-9.3.27.tgz", + "integrity": "sha512-DbRAYyL5Bd/pcFiGHPpK+rQMyc4LBll9YBy496l97dGDO2HmqFuiwP74V1KznxLcr4inCNWwThIJws5VLFsJLg==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "react-transition-group": "^4.4.1" + } + }, + "@fluentui/react-toolbar": { + "version": "9.1.66", + "resolved": "https://registry.npmjs.org/@fluentui/react-toolbar/-/react-toolbar-9.1.66.tgz", + "integrity": "sha512-ooNTp1R5MBZwiVK8fiJu29gE48vUx4NbXdwB2yHcCprasG3asjuoKQfOYM4+1NfFA0DetVrbK8L46IBeZyeBvA==", + "requires": { + "@fluentui/react-button": "^9.3.65", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-divider": "^9.2.58", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-radio": "^9.2.3", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-tooltip": { + "version": "9.4.11", + "resolved": "https://registry.npmjs.org/@fluentui/react-tooltip/-/react-tooltip-9.4.11.tgz", + "integrity": "sha512-HXm8yYuAHJuczeFExco0WQSjO3DzDj5AJxqICHF8qtbtihUKfWpPnKM1qQWR+yJR2zc2jzvOEIzZXEkxSG+fSg==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-portal": "^9.4.10", + "@fluentui/react-positioning": "^9.12.4", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-tree": { + "version": "9.4.25", + "resolved": "https://registry.npmjs.org/@fluentui/react-tree/-/react-tree-9.4.25.tgz", + "integrity": "sha512-7IMqnOiNFMRuPujnbxJUYD8AEh0z1OGXkdNkAeLyj3pkwuvQs9+TbaNtv5Z372YN+kwYF4EYalYcPuNsRlx7cQ==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.7.3", + "@fluentui/react-avatar": "^9.6.9", + "@fluentui/react-button": "^9.3.65", + "@fluentui/react-checkbox": "^9.2.8", + "@fluentui/react-context-selector": "^9.1.49", + "@fluentui/react-icons": "^2.0.224", + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-radio": "^9.2.3", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-tabster": "^9.17.3", + "@fluentui/react-theme": "^9.1.16", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-utilities": { + "version": "9.16.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-utilities/-/react-utilities-9.16.1.tgz", + "integrity": "sha512-2wdwmgTFcVy14ZLbRNJ8Q6dCCBLekkJ8Znnok68gKRLDcwpPT3UjSraoU+DGjOA5BMfPppZBU8Yb5GqdIfd48g==", + "requires": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-shared-contexts": "^9.14.0", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-virtualizer": { + "version": "9.0.0-alpha.66", + "resolved": "https://registry.npmjs.org/@fluentui/react-virtualizer/-/react-virtualizer-9.0.0-alpha.66.tgz", + "integrity": "sha512-x/ZOAIAwctt7pvOBIzS4iZGU0ahiPhQFS7iAHksFkF9LimneaV92A/02dW0Cy4v7dv9wZNoosQwhS05Yx3DVDQ==", + "requires": { + "@fluentui/react-jsx-runtime": "^9.0.27", + "@fluentui/react-shared-contexts": "^9.14.0", + "@fluentui/react-utilities": "^9.16.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/react-window-provider": { + "version": "2.2.18", + "resolved": "https://registry.npmjs.org/@fluentui/react-window-provider/-/react-window-provider-2.2.18.tgz", + "integrity": "sha512-nBKqxd0P8NmIR0qzFvka1urE2LVbUm6cse1I1T7TcOVNYa5jDf5BrO06+JRZfwbn00IJqOnIVoP0qONqceypWQ==", + "requires": { + "@fluentui/set-version": "^8.2.14", + "tslib": "^2.1.0" + } + }, + "@fluentui/set-version": { + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@fluentui/set-version/-/set-version-8.2.14.tgz", + "integrity": "sha512-f/QWJnSeyfAjGAqq57yjMb6a5ejPlwfzdExPmzFBuEOuupi8hHbV8Yno12XJcTW4I0KXEQGw+PUaM1aOf/j7jw==", + "requires": { + "tslib": "^2.1.0" + } + }, + "@fluentui/style-utilities": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/@fluentui/style-utilities/-/style-utilities-8.10.2.tgz", + "integrity": "sha512-ocELtMb/85nBa3rSfiAIwYx6TydN+3rQqv1P0H/L7etYNNtxOfS86JSWfn8zAsHMejbwUKJ1ZsIKs47c598XGQ==", + "requires": { + "@fluentui/merge-styles": "^8.5.15", + "@fluentui/set-version": "^8.2.14", + "@fluentui/theme": "^2.6.41", + "@fluentui/utilities": "^8.13.24", + "@microsoft/load-themed-styles": "^1.10.26", + "tslib": "^2.1.0" + } + }, + "@fluentui/theme": { + "version": "2.6.41", + "resolved": "https://registry.npmjs.org/@fluentui/theme/-/theme-2.6.41.tgz", + "integrity": "sha512-h9RguEzqzJ0+59ys5Kkp7JtsjhDUxBLmQunu5rpHp5Mp788OtEjI/n1a9FIcOAL/priPSQwXN7RbuDpeP7+aSw==", + "requires": { + "@fluentui/merge-styles": "^8.5.15", + "@fluentui/set-version": "^8.2.14", + "@fluentui/utilities": "^8.13.24", + "tslib": "^2.1.0" + } + }, + "@fluentui/tokens": { + "version": "1.0.0-alpha.13", + "resolved": "https://registry.npmjs.org/@fluentui/tokens/-/tokens-1.0.0-alpha.13.tgz", + "integrity": "sha512-IzYysTTBkAH7tQZxYKpzhxYnTJkvwXhjhTOpmERgnqTFifHTP8/vaQjJAAm7dI/9zlDx1oN+y/I+KzL9bDLHZQ==", + "requires": { + "@swc/helpers": "^0.5.1" + } + }, + "@fluentui/utilities": { + "version": "8.13.24", + "resolved": "https://registry.npmjs.org/@fluentui/utilities/-/utilities-8.13.24.tgz", + "integrity": "sha512-/jo6hWCzTGCx06l2baAMwsjjBZ/dyMouls53uNaQLUGUUhUwXh/DcDDXMqLRJB3MaH9zvgfvRw61iKmm2s9fIA==", + "requires": { + "@fluentui/dom-utilities": "^2.2.14", + "@fluentui/merge-styles": "^8.5.15", + "@fluentui/set-version": "^8.2.14", + "tslib": "^2.1.0" + } + }, + "@griffel/core": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@griffel/core/-/core-1.15.2.tgz", + "integrity": "sha512-RlsIXoSS3gaYykUgxFpwKAs/DV9cRUKp3CW1kt3iPAtsDTWn/o+8bT1jvBws/tMM2GBu/Uc0EkaIzUPqD7uA+Q==", + "requires": { + "@emotion/hash": "^0.9.0", + "@griffel/style-types": "^1.0.3", + "csstype": "^3.1.3", + "rtl-css-js": "^1.16.1", + "stylis": "^4.2.0", + "tslib": "^2.1.0" + } + }, + "@griffel/react": { + "version": "1.5.20", + "resolved": "https://registry.npmjs.org/@griffel/react/-/react-1.5.20.tgz", + "integrity": "sha512-1P2yaPctENFSCwyPIYXBmgpNH68c0lc/jwSzPij1QATHDK1AASKuSeq6hW108I67RKjhRyHCcALshdZ3GcQXSg==", + "requires": { + "@griffel/core": "^1.15.2", + "tslib": "^2.1.0" + } + }, + "@griffel/style-types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@griffel/style-types/-/style-types-1.0.3.tgz", + "integrity": "sha512-AzbbYV/EobNIBtfMtyu2edFin895gjVxtu1nsRhTETUAIb0/LCZoue3Jd/kFLuPwe95rv5WRUBiQpVwJsrrFcw==", + "requires": { + "csstype": "^3.1.3" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz", + "integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@microsoft/load-themed-styles": { + "version": "1.10.295", + "resolved": "https://registry.npmjs.org/@microsoft/load-themed-styles/-/load-themed-styles-1.10.295.tgz", + "integrity": "sha512-W+IzEBw8a6LOOfRJM02dTT7BDZijxm+Z7lhtOAz1+y9vQm1Kdz9jlAO+qCEKsfxtUOmKilW8DIRqFw2aUgKeGg==" + }, + "@react-spring/animated": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.3.tgz", + "integrity": "sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw==", + "requires": { + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + } + }, + "@react-spring/core": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.3.tgz", + "integrity": "sha512-IqFdPVf3ZOC1Cx7+M0cXf4odNLxDC+n7IN3MDcVCTIOSBfqEcBebSv+vlY5AhM0zw05PDbjKrNmBpzv/AqpjnQ==", + "requires": { + "@react-spring/animated": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + } + }, + "@react-spring/shared": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.3.tgz", + "integrity": "sha512-NEopD+9S5xYyQ0pGtioacLhL2luflh6HACSSDUZOwLHoxA5eku1UPuqcJqjwSD6luKjjLfiLOspxo43FUHKKSA==", + "requires": { + "@react-spring/types": "~9.7.3" + } + }, + "@react-spring/types": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.3.tgz", + "integrity": "sha512-Kpx/fQ/ZFX31OtlqVEFfgaD1ACzul4NksrvIgYfIFq9JpDHFwQkMVZ10tbo0FU/grje4rcL4EIrjekl3kYwgWw==" + }, + "@react-spring/web": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.3.tgz", + "integrity": "sha512-BXt6BpS9aJL/QdVqEIX9YoUy8CE6TJrU0mNCqSoxdXlIeNcEBWOfIyE6B14ENNsyQKS3wOWkiJfco0tCr/9tUg==", + "requires": { + "@react-spring/animated": "~9.7.3", + "@react-spring/core": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + } + }, + "@remix-run/router": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.2.tgz", + "integrity": "sha512-ACXpdMM9hmKZww21yEqWwiLws/UPLhNKvimN8RrYSqPSvB3ov7sLvAcfvaxePeLvccTQKGdkDIhLYApZVDFuKg==" + }, + "@rollup/plugin-typescript": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.3.tgz", + "integrity": "sha512-8o6cNgN44kQBcpsUJTbTXMTtb87oR1O0zgP3Dxm71hrNgparap3VujgofEilTYJo+ivf2ke6uy3/E5QEaiRlDA==", + "requires": { + "@rollup/pluginutils": "^5.0.1", + "resolve": "^1.22.1" + } + }, + "@rollup/pluginutils": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.4.tgz", + "integrity": "sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g==", + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + } + }, + "@swc/helpers": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz", + "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==", + "requires": { + "tslib": "^2.4.0" + } + }, + "@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "requires": { + "@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.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "dev": true, + "requires": { + "@babel/types": "^7.20.7" + } + }, + "@types/dompurify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.3.tgz", + "integrity": "sha512-odiGr/9/qMqjcBOe5UhcNLOFHSYmKFOyr+bJ/Xu3Qp4k1pNPAlNLUVNNLcLfjQI7+W7ObX58EdD3H+3p3voOvA==", + "dev": true, + "requires": { + "@types/trusted-types": "*" + } + }, + "@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" + }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "@types/react": { + "version": "18.2.48", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.48.tgz", + "integrity": "sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "18.2.18", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz", + "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==", + "requires": { + "@types/react": "*" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "@types/trusted-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", + "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==", + "dev": true + }, + "@vitejs/plugin-react": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", + "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", + "dev": true, + "requires": { + "@babel/core": "^7.23.5", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + } + }, + "caniuse-lite": { + "version": "1.0.30001579", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz", + "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "dompurify": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.6.tgz", + "integrity": "sha512-ilkD8YEnnGh1zJ240uJsW7AzE+2qpbOUYjacomn3AvJ6J4JhKGSZ2nh4wUIXPZrEPppaCLx5jFe8T89Rk8tQ7w==" + }, + "electron-to-chromium": { + "version": "1.4.639", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.639.tgz", + "integrity": "sha512-CkKf3ZUVZchr+zDpAlNLEEy2NJJ9T64ULWaDgy3THXXlPVPkLu3VOs9Bac44nebVtdwl2geSj6AxTtGDOxoXhg==", + "dev": true + }, + "esbuild": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.11.tgz", + "integrity": "sha512-i8u6mQF0JKJUlGR3OdFLKldJQMMs8OqM9Cc3UCi9XXziJ9WERM5bfkHaEAy0YAvPRMgqSW55W7xYn84XtEFTtA==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.18.11", + "@esbuild/android-arm64": "0.18.11", + "@esbuild/android-x64": "0.18.11", + "@esbuild/darwin-arm64": "0.18.11", + "@esbuild/darwin-x64": "0.18.11", + "@esbuild/freebsd-arm64": "0.18.11", + "@esbuild/freebsd-x64": "0.18.11", + "@esbuild/linux-arm": "0.18.11", + "@esbuild/linux-arm64": "0.18.11", + "@esbuild/linux-ia32": "0.18.11", + "@esbuild/linux-loong64": "0.18.11", + "@esbuild/linux-mips64el": "0.18.11", + "@esbuild/linux-ppc64": "0.18.11", + "@esbuild/linux-riscv64": "0.18.11", + "@esbuild/linux-s390x": "0.18.11", + "@esbuild/linux-x64": "0.18.11", + "@esbuild/netbsd-x64": "0.18.11", + "@esbuild/openbsd-x64": "0.18.11", + "@esbuild/sunos-x64": "0.18.11", + "@esbuild/win32-arm64": "0.18.11", + "@esbuild/win32-ia32": "0.18.11", + "@esbuild/win32-x64": "0.18.11" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "requires": { + "has": "^1.0.3" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "keyborg": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/keyborg/-/keyborg-2.4.1.tgz", + "integrity": "sha512-B9EZwDd36WKlIq6JmimaTsTDx5E0aUqZcxtgTfK66ut1FbRXYhBmiB7Al2qKzB7CCX9C49sTBiiyVzsXCA6J4Q==" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true + }, + "ndjson-readablestream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ndjson-readablestream/-/ndjson-readablestream-1.0.7.tgz", + "integrity": "sha512-4DDTwYTV4yRnCoXparQTF3JeahTNkLVy7XlA0RHXzAqQ3uU8vcu97bNW8rXAQOKQVJGs2aZoX+7cbvfs0LENEA==" + }, + "node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "requires": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "dependencies": { + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "requires": { + "loose-envify": "^1.1.0" + } + } + } + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true + }, + "react-router": { + "version": "6.21.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.21.3.tgz", + "integrity": "sha512-a0H638ZXULv1OdkmiK6s6itNhoy33ywxmUFT/xtSoVyf9VnC7n7+VT4LjVzdIHSaF5TIh9ylUgxMXksHTgGrKg==", + "requires": { + "@remix-run/router": "1.14.2" + } + }, + "react-router-dom": { + "version": "6.21.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.21.3.tgz", + "integrity": "sha512-kNzubk7n4YHSrErzjLK72j0B5i969GsuCGazRl3G6j1zqZBLjuSlYBdVdkDOgzGdPIffUOc9nmgiadTEVoq91g==", + "requires": { + "@remix-run/router": "1.14.2", + "react-router": "6.21.3" + } + }, + "react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, + "regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "resolve": { + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "requires": { + "fsevents": "~2.3.2" + } + }, + "rtl-css-js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", + "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, + "scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "stylis": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", + "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "tabster": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/tabster/-/tabster-5.2.0.tgz", + "integrity": "sha512-cSi3a0gGeM9Co/gTKHlhTFfiitwVjcA+kP9lJux0U7QaRrZox1yYrfbwZhJXM7N0fux7BgvCYaOxME5k0EQ0tA==", + "requires": { + "keyborg": "^2.2.0", + "tslib": "^2.3.1" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==" + }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "use-disposable": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/use-disposable/-/use-disposable-1.0.2.tgz", + "integrity": "sha512-UMaXVlV77dWOu4GqAFNjRzHzowYKUKbJBQfCexvahrYeIz4OkUYUjna4Tjjdf92NH8Nm8J7wEfFRgTIwYjO5jg==", + "requires": {} + }, + "vite": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", + "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", + "dev": true, + "requires": { + "esbuild": "^0.18.10", + "fsevents": "~2.3.2", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } +} diff --git a/app/frontend/package.json b/app/frontend/package.json new file mode 100644 index 0000000..5ee802e --- /dev/null +++ b/app/frontend/package.json @@ -0,0 +1,38 @@ +{ + "name": "frontend", + "private": true, + "version": "1.0.0-alpha", + "type": "module", + "engines": { + "node": ">=14.0.0" + }, + "scripts": { + "dev": "vite --port=8081", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@azure/msal-react": "^2.0.4", + "@azure/msal-browser": "^3.1.0", + "@fluentui/react": "^8.112.5", + "@fluentui/react-components": "^9.37.3", + "@fluentui/react-icons": "^2.0.221", + "@react-spring/web": "^9.7.3", + "dompurify": "^3.0.6", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.18.0", + "ndjson-readablestream": "^1.0.7", + "scheduler": "^0.20.2" + }, + "devDependencies": { + "@types/dompurify": "^3.0.3", + "@types/react": "^18.2.34", + "@types/react-dom": "^18.2.14", + "@vitejs/plugin-react": "^4.1.1", + "prettier": "^3.0.3", + "typescript": "^5.2.2", + "vite": "^4.5.3" + + } +} diff --git a/app/frontend/public/favicon.ico b/app/frontend/public/favicon.ico new file mode 100644 index 0000000..f1fe505 Binary files /dev/null and b/app/frontend/public/favicon.ico differ diff --git a/app/frontend/src/api/api.ts b/app/frontend/src/api/api.ts new file mode 100644 index 0000000..fb8f511 --- /dev/null +++ b/app/frontend/src/api/api.ts @@ -0,0 +1,51 @@ +import { ChatAppResponse, ChatAppResponseOrError, ChatAppRequest } from "./models"; +import { useLogin } from "../authConfig"; + +const BACKEND_URI = import.meta.env.VITE_BACKEND_URI ? import.meta.env.VITE_BACKEND_URI : ""; + +function getHeaders(idToken: string | undefined, stream:boolean): Record { + var headers: Record = { + "Content-Type": "application/json" + }; + // If using login, add the id token of the logged in account as the authorization + if (useLogin) { + if (idToken) { + headers["Authorization"] = `Bearer ${idToken}` + } + } + + if (stream) { + headers["Accept"] = "application/x-ndjson"; + } else { + headers["Accept"] = "application/json"; + } + + return headers; +} + +export async function askApi(request: ChatAppRequest, idToken: string | undefined): Promise { + const response = await fetch(`${BACKEND_URI}/ask`, { + method: "POST", + headers: getHeaders(idToken, request.stream || false), + body: JSON.stringify(request) + }); + + const parsedResponse: ChatAppResponseOrError = await response.json(); + if (response.status > 299 || !response.ok) { + throw Error(parsedResponse.error || "Unknown error"); + } + + return parsedResponse as ChatAppResponse; +} + +export async function chatApi(request: ChatAppRequest, idToken: string | undefined): Promise { + return await fetch(`${BACKEND_URI}/chat`, { + method: "POST", + headers: getHeaders(idToken, request.stream || false), + body: JSON.stringify(request) + }); +} + +export function getCitationFilePath(citation: string): string { + return `${BACKEND_URI}/content/${citation}`; +} diff --git a/app/frontend/src/api/index.ts b/app/frontend/src/api/index.ts new file mode 100644 index 0000000..0475d35 --- /dev/null +++ b/app/frontend/src/api/index.ts @@ -0,0 +1,2 @@ +export * from "./api"; +export * from "./models"; diff --git a/app/frontend/src/api/models.ts b/app/frontend/src/api/models.ts new file mode 100644 index 0000000..c468488 --- /dev/null +++ b/app/frontend/src/api/models.ts @@ -0,0 +1,70 @@ +export const enum Approaches { + JAVA_OPENAI_SDK = "jos", + JAVA_SEMANTIC_KERNEL = "jsk", + JAVA_SEMANTIC_KERNEL_PLANNER = "jskp" +} + +export const enum RetrievalMode { + Hybrid = "hybrid", + Vectors = "vectors", + Text = "text" +} + +export const enum SKMode { + Chains = "chains", + Planner = "planner" +} + +export type ChatAppRequestOverrides = { + retrieval_mode?: RetrievalMode; + semantic_ranker?: boolean; + semantic_captions?: boolean; + exclude_category?: string; + top?: number; + temperature?: number; + prompt_template?: string; + prompt_template_prefix?: string; + prompt_template_suffix?: string; + suggest_followup_questions?: boolean; + use_oid_security_filter?: boolean; + use_groups_security_filter?: boolean; + semantic_kernel_mode?: SKMode; +}; + +export type ResponseMessage = { + content: string; + role: string; +}; + +export type ResponseContext = { + thoughts: string | null; + data_points: string[]; +}; + +export type ResponseChoice = { + index: number; + message: ResponseMessage; + context: ResponseContext; + session_state: any; +}; + +export type ChatAppResponseOrError = { + choices?: ResponseChoice[]; + error?: string; +}; + +export type ChatAppResponse = { + choices: ResponseChoice[]; +}; + +export type ChatAppRequestContext = { + overrides?: ChatAppRequestOverrides; +}; + +export type ChatAppRequest = { + messages: ResponseMessage[]; + approach: Approaches; + context?: ChatAppRequestContext; + stream?: boolean; + session_state: any; +}; diff --git a/app/frontend/src/assets/github.svg b/app/frontend/src/assets/github.svg new file mode 100644 index 0000000..d5e6491 --- /dev/null +++ b/app/frontend/src/assets/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/frontend/src/assets/search.svg b/app/frontend/src/assets/search.svg new file mode 100644 index 0000000..feadc50 --- /dev/null +++ b/app/frontend/src/assets/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/frontend/src/authConfig.ts b/app/frontend/src/authConfig.ts new file mode 100644 index 0000000..7e583ab --- /dev/null +++ b/app/frontend/src/authConfig.ts @@ -0,0 +1,89 @@ +// Refactored from https://github.com/Azure-Samples/ms-identity-javascript-react-tutorial/blob/main/1-Authentication/1-sign-in/SPA/src/authConfig.js + +import { AuthenticationResult, IPublicClientApplication } from "@azure/msal-browser"; + +const BACKEND_URI = import.meta.env.VITE_BACKEND_URI ? import.meta.env.VITE_BACKEND_URI : ""; + +interface AuthSetup { + // Set to true if login elements should be shown in the UI + useLogin: boolean; + /** + * Configuration object to be passed to MSAL instance on creation. + * For a full list of MSAL.js configuration parameters, visit: + * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/configuration.md + */ + msalConfig: { + auth: { + clientId: string; // Client app id used for login + authority: string; // Directory to use for login https://learn.microsoft.com/azure/active-directory/develop/msal-client-application-configuration#authority + redirectUri: string; // Points to window.location.origin. You must register this URI on Azure Portal/App Registration. + postLogoutRedirectUri: string; // Indicates the page to navigate after logout. + navigateToLoginRequestUrl: boolean; // If "true", will navigate back to the original request location before processing the auth code response. + }; + cache: { + cacheLocation: string; // Configures cache location. "sessionStorage" is more secure, but "localStorage" gives you SSO between tabs. + storeAuthStateInCookie: boolean; // Set this to "true" if you are having issues on IE11 or Edge + }; + }; + loginRequest: { + /** + * Scopes you add here will be prompted for user consent during sign-in. + * By default, MSAL.js will add OIDC scopes (openid, profile, email) to any login request. + * For more information about OIDC scopes, visit: + * https://docs.microsoft.com/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes + */ + scopes: Array; + }; + tokenRequest: { + scopes: Array; + }; +} + +// Fetch the auth setup JSON data from the API if not already cached +async function fetchAuthSetup(): Promise { + const response = await fetch(`${BACKEND_URI}/auth_setup`); + if (!response.ok) { + throw new Error(`auth setup response was not ok: ${response.status}`); + } + return await response.json(); +} + +const authSetup = await fetchAuthSetup(); + +export const useLogin = authSetup.useLogin; + +/** + * Configuration object to be passed to MSAL instance on creation. + * For a full list of MSAL.js configuration parameters, visit: + * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/configuration.md + */ +export const msalConfig = authSetup.msalConfig; + +/** + * Scopes you add here will be prompted for user consent during sign-in. + * By default, MSAL.js will add OIDC scopes (openid, profile, email) to any login request. + * For more information about OIDC scopes, visit: + * https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes + */ +export const loginRequest = authSetup.loginRequest; + +const tokenRequest = authSetup.tokenRequest; + +// Build an absolute redirect URI using the current window's location and the relative redirect URI from auth setup +export const getRedirectUri = () => { + return window.location.origin + authSetup.msalConfig.auth.redirectUri; +}; + +// Get an access token for use with the API server. +// ID token received when logging in may not be used for this purpose because it has the incorrect audience +export const getToken = (client: IPublicClientApplication): Promise => { + return client + .acquireTokenSilent({ + ...tokenRequest, + redirectUri: getRedirectUri() + }) + .catch(error => { + console.log(error); + return undefined; + }); +}; diff --git a/app/frontend/src/components/AnalysisPanel/AnalysisPanel.module.css b/app/frontend/src/components/AnalysisPanel/AnalysisPanel.module.css new file mode 100644 index 0000000..909ac03 --- /dev/null +++ b/app/frontend/src/components/AnalysisPanel/AnalysisPanel.module.css @@ -0,0 +1,6 @@ +.thoughtProcess { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; + word-wrap: break-word; + padding-top: 12px; + padding-bottom: 12px; +} diff --git a/app/frontend/src/components/AnalysisPanel/AnalysisPanel.tsx b/app/frontend/src/components/AnalysisPanel/AnalysisPanel.tsx new file mode 100644 index 0000000..4b99a41 --- /dev/null +++ b/app/frontend/src/components/AnalysisPanel/AnalysisPanel.tsx @@ -0,0 +1,57 @@ +import { Pivot, PivotItem } from "@fluentui/react"; +import DOMPurify from "dompurify"; + +import styles from "./AnalysisPanel.module.css"; + +import { SupportingContent } from "../SupportingContent"; +import { ChatAppResponse } from "../../api"; +import { AnalysisPanelTabs } from "./AnalysisPanelTabs"; + +interface Props { + className: string; + activeTab: AnalysisPanelTabs; + onActiveTabChanged: (tab: AnalysisPanelTabs) => void; + activeCitation: string | undefined; + citationHeight: string; + answer: ChatAppResponse; +} + +const pivotItemDisabledStyle = { disabled: true, style: { color: "grey" } }; + +export const AnalysisPanel = ({ answer, activeTab, activeCitation, citationHeight, className, onActiveTabChanged }: Props) => { + const isDisabledThoughtProcessTab: boolean = !answer.choices[0].context.thoughts; + const isDisabledSupportingContentTab: boolean = !answer.choices[0].context.data_points.length; + const isDisabledCitationTab: boolean = !activeCitation; + + const sanitizedThoughts = DOMPurify.sanitize(answer.choices[0].context.thoughts!); + + return ( + pivotItem && onActiveTabChanged(pivotItem.props.itemKey! as AnalysisPanelTabs)} + > + +
+
+ + + + +