diff --git a/.github/workflows/backend_check.yml b/.github/workflows/backend_check.yml new file mode 100644 index 00000000..13fa5abd --- /dev/null +++ b/.github/workflows/backend_check.yml @@ -0,0 +1,76 @@ +name: check backend + +on: + push: + branches: + - dev + - master + pull_request: + branches: + - dev + +jobs: + check_backend_codestyle: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: set up python 3.10 + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: setup poetry and install dependencies + run: | + python -m pip install --upgrade pip poetry + python -m poetry lock --no-update + python -m poetry install --with lint --no-interaction + working-directory: backend/df_designer + + - name: run black codestyle + run: | + python -m poetry run black --line-length=120 --check . + working-directory: backend/df_designer + + - name: run flake8 codestyle + run: | + python -m poetry run flake8 --max-line-length 120 --ignore=E203 . + working-directory: backend/df_designer + + - name: run isort codestyle + run: | + python -m poetry run isort --line-length=120 --diff . + working-directory: backend/df_designer + + test_backend: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: set up python 3.10 + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: setup poetry and install dependencies + run: | + python -m pip install --upgrade pip poetry + python -m poetry lock --no-update + python -m poetry install --with lint --no-interaction + working-directory: backend/df_designer + + - name: build wheel + run: | + python -m poetry build + working-directory: backend/df_designer + + - name: Create new project + run: | + python -m poetry run dflowd init --destination ../../ --no-input --overwrite-if-exists + working-directory: backend/df_designer + + - name: run tests + run: | + python -m poetry install + python -m poetry run pytest ../backend/df_designer/app/tests/ --verbose + working-directory: df_designer_project diff --git a/.github/workflows/build_and_upload_release.yml b/.github/workflows/build_and_upload_release.yml new file mode 100644 index 00000000..4a509c24 --- /dev/null +++ b/.github/workflows/build_and_upload_release.yml @@ -0,0 +1,45 @@ +name: build_and_upload_release + +on: + release: + types: + - published + +jobs: + build: + name: build and upload release + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: set up python + uses: actions/setup-python@v5 + + - name: setup poetry + run: | + python -m pip install --upgrade pip poetry + + - name: build wheels and test uploading to pypi + if: startsWith(github.ref, 'refs/tags/v') != true + run: | + python -m poetry --build publish --dry-run + working-directory: backend/df_designer + + - name: build wheels and upload to pypi + if: startsWith(github.ref, 'refs/tags/v') + env: + POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }} + run: | + python -m poetry --build publish + working-directory: backend/df_designer + + - name: upload binaries into release + if: startsWith(github.ref, 'refs/tags/v') + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: backend/df_designer/dist/* + tag: ${{ github.ref }} + overwrite: true + file_glob: true diff --git a/.github/workflows/docker_check.yml b/.github/workflows/docker_check.yml new file mode 100644 index 00000000..ac7c5795 --- /dev/null +++ b/.github/workflows/docker_check.yml @@ -0,0 +1,33 @@ +name: Build Docker Images + +on: + push: + branches: + - dev + - master + pull_request: + branches: + - dev + +jobs: + build_images: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: setup poetry and install dependencies + run: | + python -m pip install --upgrade pip poetry + python -m poetry lock --no-update + python -m poetry install --with lint --no-ansi --no-interaction + working-directory: backend/df_designer + + - name: Create new project + run: python -m poetry run dflowd init --destination ../../ --no-input --overwrite-if-exists + working-directory: backend/df_designer + + - name: Build Frontend + run: docker build -f Dockerfile --build-arg PROJECT_DIR=df_designer_project --target=frontend-builder . + + - name: Build backend & run app + run: docker build -f Dockerfile --build-arg PROJECT_DIR=df_designer_project --target=runtime . diff --git a/.github/workflows/e2e_test.yml b/.github/workflows/e2e_test.yml new file mode 100644 index 00000000..92321216 --- /dev/null +++ b/.github/workflows/e2e_test.yml @@ -0,0 +1,139 @@ +# name: test app + +# on: +# push: +# branches: +# - dev +# pull_request: +# branches: +# - dev + +# jobs: + +# build_frontend: +# runs-on: ubuntu-latest + +# steps: +# - uses: actions/checkout@v4 + +# - name: Install bun +# run: npm install -g bun + +# - name: Install frontend dependencies +# run: bun install +# working-directory: frontend + +# - name: Build frontend +# run: bun run build +# working-directory: frontend + +# - run: touch file1.txt + +# - name: Archive frontend dist +# uses: actions/upload-artifact@v4 +# with: +# name: frontend-dist +# path: frontend/dist + + +# build_backend: +# runs-on: ubuntu-latest +# needs: build_frontend +# steps: +# - uses: actions/checkout@v4 + +# - name: Create dist directory +# run: mkdir -p frontend/dist + +# - name: Download frontend dist +# uses: actions/download-artifact@v4 +# with: +# name: frontend-dist +# path: frontend/dist + +# - name: copy static files +# run: | +# cp -r frontend/dist/. backend/df_designer/app/static/ + +# - name: set up python 3.10 +# uses: actions/setup-python@v5 +# with: +# python-version: '3.10' + +# - name: setup poetry and install dependencies +# run: | +# python -m pip install --upgrade pip poetry +# python -m poetry lock --no-update +# python -m poetry install --with lint --no-interaction +# working-directory: backend/df_designer + +# - name: build wheel +# run: python -m poetry build +# working-directory: backend/df_designer + +# - name: Archive backend dist +# uses: actions/upload-artifact@v4 +# with: +# name: backend-dist +# path: backend/df_designer/dist + + +# run_app: +# runs-on: ubuntu-latest +# needs: build_backend +# steps: +# - uses: actions/checkout@v4 + +# - name: set up python 3.10 +# uses: actions/setup-python@v5 +# with: +# python-version: '3.10' + +# - name: setup dflowd poetry and install dependencies +# run: | +# python -m pip install --upgrade pip poetry +# python -m poetry lock --no-update +# python -m poetry install --with lint --no-interaction +# working-directory: backend/df_designer + +# - name: Create new project +# run: | +# python -m poetry run dflowd init --destination ../../ --no-input --overwrite-if-exists +# working-directory: backend/df_designer + +# - name: Create dist directory +# run: mkdir -p backend/df_designer/dist + +# - name: Download backend dist +# uses: actions/download-artifact@v4 +# with: +# name: backend-dist +# path: backend/df_designer/dist + +# - name: setup project poetry and install dependencies +# run: | +# python -m pip install --upgrade pip poetry +# python -m poetry lock --no-update +# python -m poetry install --no-interaction +# working-directory: df_designer_project + +# - name: Run back & front +# run: | +# python -m poetry run dflowd run_backend & +# sleep 10 +# working-directory: df_designer_project + +# - name: Install bun +# run: npm install -g bun + +# - name: Install frontend dependencies +# run: bun install +# working-directory: frontend + +# - name: Cypress run +# uses: cypress-io/github-action@v6 +# with: +# install-command: bun add cypress +# command: bun run e2e:chrome +# working-directory: frontend +# browser: chrome diff --git a/.github/workflows/frontend_check.yml b/.github/workflows/frontend_check.yml new file mode 100644 index 00000000..8be0b0a2 --- /dev/null +++ b/.github/workflows/frontend_check.yml @@ -0,0 +1,16 @@ +# name: front check + +# on: [push, pull_request] + +# jobs: +# build_and_check_frontend: +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v4 + +# - name: Install bun +# run: npm install -g bun + +# - name: Install dependencies +# run: bun install +# working-directory: frontend diff --git a/.gitignore b/.gitignore index 68bc17f9..7752fb9b 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,91 @@ share/python-wheels/ *.egg MANIFEST +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# IDEs and editors +.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +.sass-cache +connect.lock +typings + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + + +# Dependency directories +node_modules/ +jspm_packages/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# next.js build output +.next + +# Lerna +lerna-debug.log + +# System Files +.DS_Store +Thumbs.db + # 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. @@ -158,3 +243,17 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +.vscode +/df_designer_front/node_modules +/df_designer_front/vscode +/df_designer_front/.vscode + +./flows.json +*.sqlite +my_project +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +df_designer_project diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..e69de29b diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..7ee29af6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,71 @@ +FROM oven/bun:1 as frontend-base +FROM frontend-base AS frontend-builder + +WORKDIR /temp +COPY ./frontend/package.json /temp/frontend/package.json +COPY ./frontend/bun.lockb /temp/frontend/bun.lockb + +RUN cd /temp/frontend && bun install --frozen-lockfile + +# Copy the rest of the application code +COPY ./frontend/ /temp/frontend/ +WORKDIR /temp/frontend/ + +RUN bun run build + +#--------------------------------------------------------- + +# Use a slim variant to reduce image size where possible +FROM python:3.10-slim as backend-builder + +WORKDIR /temp + +ARG PROJECT_DIR +# ENV PROJECT_DIR ${PROJECT_DIR} + +ENV POETRY_VERSION=1.8.2 \ + POETRY_HOME=/poetry \ + POETRY_VENV=/poetry-venv + +# Install Poetry in a virtual environment +RUN python3 -m venv $POETRY_VENV \ + && $POETRY_VENV/bin/pip install -U pip setuptools \ + && $POETRY_VENV/bin/pip install poetry==$POETRY_VERSION + +ENV PATH="${PATH}:${POETRY_VENV}/bin" + +COPY ./backend/df_designer /temp/backend/df_designer +COPY --from=frontend-builder /temp/frontend/dist /temp/backend/df_designer/app/static + +COPY ./${PROJECT_DIR} /temp/${PROJECT_DIR} + +# Build the wheel +WORKDIR /temp/backend/df_designer +RUN poetry build + +#--------------------------------------------------------- + +#TODO: create something like src named e.g. runtime/ + +FROM python:3.10-slim as runtime + +ARG PROJECT_DIR + +COPY --from=backend-builder /poetry-venv /poetry-venv + +# Set environment variable to use the virtualenv +ENV PATH="/poetry-venv/bin:$PATH" + +# Copy only the necessary files +COPY --from=backend-builder /temp/backend/df_designer /src2/backend/df_designer +COPY ./${PROJECT_DIR} /src2/project_dir + +# Install the wheel +WORKDIR /src2/project_dir +RUN poetry lock --no-update \ + && poetry install + +CMD ["poetry", "run", "dflowd", "run_backend"] + + +# #TODO: change scr to app (maybe) \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..c6380440 --- /dev/null +++ b/Makefile @@ -0,0 +1,138 @@ +SHELL = /bin/bash + +PYTHON = python3 +FRONTEND_DIR = ./frontend +BACKEND_DIR = ./backend/df_designer + + +.PHONY: help +help: + @echo "Usage: make " + @echo "" + @echo "Available targets:" + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " %-20s : %s\n", $$1, $$2}' | grep -v 'make .* &&' + + @echo "" + @echo "These targets are for internal use only:" + @echo "check_project_arg, " + + +# frontend cmds +.PHONY: install_frontend_env +install_frontend_env: ## Installs frontend dependencies using bun + cd ${FRONTEND_DIR} && bun install + +.PHONY: clean_frontend_env +clean_frontend_env: ## Removes node_modules directory + cd ${FRONTEND_DIR} && rm -rf node_modules + +.PHONY: build_frontend +build_frontend: install_frontend_env ## Builds frontend + cd ${FRONTEND_DIR} && bun run build + +.PHONY: run_frontend +run_frontend: install_frontend_env ## Does same as run_dev_frontend + cd ${FRONTEND_DIR} && bun run dev + +.PHONY: run_dev_frontend +run_dev_frontend: install_frontend_env ## Runs frontend in dev mode + make run_frontend + + +# backend cmds +.PHONY: install_backend_env +install_backend_env: ## Installs backend dependencies using poetry + cd ${BACKEND_DIR} && poetry install + +.PHONY: clean_backend_env +clean_backend_env: ## Removes backend dependencies using poetry + cd ${BACKEND_DIR} && poetry install_env remove --all + +.PHONY: build_backend +build_backend: install_backend_env ## Builds the backend wheel + cd ${BACKEND_DIR} && poetry build + +.PHONY: check_project_arg +check_project_arg: + @if [ -z "$(PROJECT_NAME)" ]; then \ + echo "PROJECT_NAME is not defined. Please pass PROJECT_NAME= with the command."; \ + exit 1; \ + fi + +.PHONY: run_backend +run_backend: check_project_arg ## Runs backend using the built dist. NEEDS arg: PROJECT_NAME + cd ${PROJECT_NAME} && poetry install && poetry run dflowd run_backend --conf-reload="False" + +.PHONY: run_dev_backend +run_dev_backend: check_project_arg install_backend_env ## Runs backend in dev mode. NEEDS arg: PROJECT_NAME + cd ${BACKEND_DIR} && poetry run dflowd run_backend --project-dir ../../${PROJECT_NAME} + +# backend tests +.PHONY: unit_tests +unit_tests: install_backend_env ## Runs all backend unit tests + cd ${BACKEND_DIR} && poetry run pytest ./app/tests/api + cd ${BACKEND_DIR} && poetry run pytest ./app/tests/services + +.PHONY: integration_tests +integration_tests: build_backend ## Runs all backend integration tests + if [ ! -d "./df_designer_project" ]; then \ + cd "${BACKEND_DIR}" && \ + poetry run dflowd init --destination ../../ --no-input --overwrite-if-exists; \ + fi + + cd df_designer_project && \ + poetry install && \ + poetry run pytest ../${BACKEND_DIR}/app/tests/integration + + +.PHONY: backend_e2e_test +backend_e2e_test: build_backend ## Runs e2e backend test + if [ ! -d "./df_designer_project" ]; then \ + cd "${BACKEND_DIR}" && \ + poetry run dflowd init --destination ../../ --no-input --overwrite-if-exists; \ + fi + + cd df_designer_project && \ + poetry install && \ + poetry run pytest ../${BACKEND_DIR}/app/tests/e2e + + +.PHONY: backend_tests +backend_tests: ## Runs all backend tests + make unit_tests + make integration_tests + make backend_e2e_test + + +# app cmds +.PHONY: install_env +install_env: ## Installs frontend & backend deps + make install_frontend_env + make install_backend_env + +.PHONY: clean_env +clean_env: ## Removes frontend & backend deps + make clean_frontend_env + make clean_backend_env + +.PHONY: build +build: install_env ## Builds both frontend & backend + make build_frontend + make build_backend + +.PHONY: run_app +run_app: check_project_arg install_env build_frontend ## Builds frontend and backend then runs the app. NEEDS arg: PROJECT_NAME + cp ${FRONTEND_DIR}/dist/* ${BACKEND_DIR}/app/static/ && \ + make build_backend && \ + make run_backend PROJECT_NAME=${PROJECT_NAME} + +.PHONY: run_dev +run_dev: check_project_arg install_env ## Runs both backend and frontend in dev mode. NEEDS arg: PROJECT_NAME + make run_dev_backend PROJECT_NAME=${PROJECT_NAME} & + make run_dev_frontend + + + +.PHONY: init_proj +init_proj: install_backend_env ## Initiates a new project using dflowd + cd ${BACKEND_DIR} && poetry run dflowd init --destination ../../ diff --git a/README.md b/README.md new file mode 100644 index 00000000..58b713b0 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# Quick Start +## System Requirements +Ensure you have Python version 3.10 or higher installed. + +## Installation +To install the necessary package, run the following command: +```bash +pip install dflowd==0.1.0b0 +``` + +## Project Initiation +Initialize your project by running: +```bash +dflowd init +cd # enter the slug you choose for your project with the help of the previous command +``` +The `dflowd init` command will start an interactive `cookiecutter` process to create a project based on a predefined template. The resulting project will be a simple example template that you can customize to suit your needs. + +## Running Your Project +To run your project, use the following command: +```bash +dflowd run_backend +``` +Note: Currently, the project runs exclusively on port 8000. diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 00000000..3df055e3 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,46 @@ +# Use a slim variant to reduce image size where possible +FROM python:3.10-slim as builder + +WORKDIR /src + +ARG PROJECT_DIR +# ENV PROJECT_DIR ${PROJECT_DIR} + +ENV POETRY_VERSION=1.8.2 \ + POETRY_HOME=/poetry \ + POETRY_VENV=/poetry-venv + +# Install Poetry in a virtual environment +RUN python3 -m venv $POETRY_VENV \ + && $POETRY_VENV/bin/pip install -U pip setuptools \ + && $POETRY_VENV/bin/pip install poetry==$POETRY_VERSION + +ENV PATH="${PATH}:${POETRY_VENV}/bin" + +COPY ./df_designer /src/df_designer +COPY ./${PROJECT_DIR} /src/${PROJECT_DIR} + +# Build the wheel +WORKDIR /src/df_designer +RUN poetry build + + +FROM python:3.10-slim as runtime + +ARG PROJECT_DIR + +COPY --from=builder /poetry-venv /poetry-venv + +# Set environment variable to use the virtualenv +ENV PATH="/poetry-venv/bin:$PATH" + +# Copy only the necessary files +COPY --from=builder /src/df_designer /df_designer +COPY --from=builder /src/${PROJECT_DIR} /${PROJECT_DIR} + +# Install the wheel +WORKDIR /${PROJECT_DIR} +RUN poetry lock --no-update \ + && poetry install + +CMD ["poetry", "run", "dflowd", "run_backend"] diff --git a/backend/df_designer/README.md b/backend/df_designer/README.md new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/__init__.py b/backend/df_designer/app/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/api/__init_.py b/backend/df_designer/app/api/__init_.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/api/api_v1/__init__.py b/backend/df_designer/app/api/api_v1/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/api/api_v1/api.py b/backend/df_designer/app/api/api_v1/api.py new file mode 100644 index 00000000..d6e857e6 --- /dev/null +++ b/backend/df_designer/app/api/api_v1/api.py @@ -0,0 +1,10 @@ +from fastapi import APIRouter + +from app.api.api_v1.endpoints import bot, dff_services, flows +from app.core.config import settings + +api_router = APIRouter() + +api_router.include_router(flows.router, prefix="/".join([settings.API_V1_STR, "flows"]), tags=["flows"]) +api_router.include_router(dff_services.router, prefix="/".join([settings.API_V1_STR, "services"]), tags=["services"]) +api_router.include_router(bot.router, prefix="/".join([settings.API_V1_STR, "bot"]), tags=["bot"]) diff --git a/backend/df_designer/app/api/api_v1/endpoints/__init__.py b/backend/df_designer/app/api/api_v1/endpoints/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/api/api_v1/endpoints/auth.py b/backend/df_designer/app/api/api_v1/endpoints/auth.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/api/api_v1/endpoints/bot.py b/backend/df_designer/app/api/api_v1/endpoints/bot.py new file mode 100644 index 00000000..b6c8ee38 --- /dev/null +++ b/backend/df_designer/app/api/api_v1/endpoints/bot.py @@ -0,0 +1,171 @@ +import asyncio +from typing import Optional, Union + +from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, WebSocket, WebSocketException, status + +from app.api import deps +from app.core.logger_config import get_logger +from app.schemas.pagination import Pagination +from app.schemas.preset import Preset +from app.services.process_manager import BuildManager, ProcessManager, RunManager +from app.services.websocket_manager import WebSocketManager + +router = APIRouter() + +logger = get_logger(__name__) + + +async def _stop_process(id_: int, process_manager: ProcessManager, process="run"): + try: + await process_manager.stop(id_) + except (RuntimeError, ProcessLookupError) as e: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Process not found. It may have already exited or not started yet. Please check logs.", + ) from e + + logger.info("%s process '%s' has stopped", process.capitalize(), id_) + return {"status": "ok"} + + +async def _check_process_status(id_: int, process_manager: ProcessManager) -> dict[str, str]: + if id_ not in process_manager.processes: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Process not found. It may have already exited.", + ) + process_status = await process_manager.get_status(id_) + return {"status": process_status.value} + + +@router.post("/build/start", status_code=201) +async def start_build( + preset: Preset, background_tasks: BackgroundTasks, build_manager: BuildManager = Depends(deps.get_build_manager) +): + await asyncio.sleep(preset.wait_time) + build_id = await build_manager.start(preset) + background_tasks.add_task(build_manager.check_status, build_id) + logger.info("Build process '%s' has started", build_id) + return {"status": "ok", "build_id": build_id} + + +@router.get("/build/stop/{build_id}", status_code=200) +async def stop_build(*, build_id: int, build_manager: BuildManager = Depends(deps.get_build_manager)): + return await _stop_process(build_id, build_manager, process="build") + + +@router.get("/build/status/{build_id}", status_code=200) +async def check_build_status(*, build_id: int, build_manager: BuildManager = Depends(deps.get_build_manager)): + return await _check_process_status(build_id, build_manager) + + +@router.get("/builds", response_model=Optional[Union[list, dict]], status_code=200) +async def check_build_processes( + build_id: Optional[int] = None, + build_manager: BuildManager = Depends(deps.get_build_manager), + run_manager: RunManager = Depends(deps.get_run_manager), + pagination: Pagination = Depends(), +): + if build_id is not None: + return await build_manager.get_build_info(build_id, run_manager) + else: + return await build_manager.get_full_info_with_runs_info( + run_manager, offset=pagination.offset(), limit=pagination.limit + ) + + +@router.get("/builds/logs/{build_id}", response_model=Optional[list], status_code=200) +async def get_build_logs( + build_id: int, build_manager: BuildManager = Depends(deps.get_build_manager), pagination: Pagination = Depends() +): + if build_id is not None: + return await build_manager.fetch_build_logs(build_id, pagination.offset(), pagination.limit) + + +@router.post("/run/start/{build_id}", status_code=201) +async def start_run( + *, + build_id: int, + preset: Preset, + background_tasks: BackgroundTasks, + run_manager: RunManager = Depends(deps.get_run_manager) +): + await asyncio.sleep(preset.wait_time) + run_id = await run_manager.start(build_id, preset) + background_tasks.add_task(run_manager.check_status, run_id) + logger.info("Run process '%s' has started", run_id) + return {"status": "ok", "run_id": run_id} + + +@router.get("/run/stop/{run_id}", status_code=200) +async def stop_run(*, run_id: int, run_manager: RunManager = Depends(deps.get_run_manager)): + return await _stop_process(run_id, run_manager, process="run") + + +@router.get("/run/status/{run_id}", status_code=200) +async def check_run_status(*, run_id: int, run_manager: RunManager = Depends(deps.get_run_manager)): + return await _check_process_status(run_id, run_manager) + + +@router.get("/runs", response_model=Optional[Union[list, dict]], status_code=200) +async def check_run_processes( + run_id: Optional[int] = None, + run_manager: RunManager = Depends(deps.get_run_manager), + pagination: Pagination = Depends(), +): + if run_id is not None: + return await run_manager.get_run_info(run_id) + else: + return await run_manager.get_full_info(offset=pagination.offset(), limit=pagination.limit) + + +@router.get("/runs/logs/{run_id}", response_model=Optional[list], status_code=200) +async def get_run_logs( + run_id: int, run_manager: RunManager = Depends(deps.get_run_manager), pagination: Pagination = Depends() +): + if run_id is not None: + return await run_manager.fetch_run_logs(run_id, pagination.offset(), pagination.limit) + + +@router.websocket("/run/connect") +async def connect( + websocket: WebSocket, + websocket_manager: WebSocketManager = Depends(deps.get_websocket_manager), + run_manager: RunManager = Depends(deps.get_run_manager), +): + """Establish a WebSocket connection to communicate with an active bot identified by its 'run_id'. + The WebSocket URL should adhere to the format: /bot/run/connect?run_id=. + """ + logger.debug("Connecting to websocket") + run_id = websocket.query_params.get("run_id") + + # Validate run_id + if run_id is None: + logger.error("No run_id provided") + raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION) + if not run_id.isdigit(): + logger.error("A non-digit run run_id provided") + raise WebSocketException(code=status.WS_1003_UNSUPPORTED_DATA) + run_id = int(run_id) + if run_id not in run_manager.processes: + logger.error("process with run_id '%s' exited or never existed", run_id) + raise WebSocketException(code=status.WS_1014_BAD_GATEWAY) + + await websocket_manager.connect(websocket) + logger.info("Websocket for run process '%s' has been opened", run_id) + + await websocket.send_text("Start chatting") + + output_task = asyncio.create_task( + websocket_manager.send_process_output_to_websocket(run_id, run_manager, websocket) + ) + input_task = asyncio.create_task( + websocket_manager.forward_websocket_messages_to_process(run_id, run_manager, websocket) + ) + + # Wait for either task to finish + _, websocket_manager.pending_tasks[websocket] = await asyncio.wait( + [output_task, input_task], + return_when=asyncio.FIRST_COMPLETED, + ) + websocket_manager.disconnect(websocket) diff --git a/backend/df_designer/app/api/api_v1/endpoints/dff_services.py b/backend/df_designer/app/api/api_v1/endpoints/dff_services.py new file mode 100644 index 00000000..904a4201 --- /dev/null +++ b/backend/df_designer/app/api/api_v1/endpoints/dff_services.py @@ -0,0 +1,21 @@ +from fastapi import APIRouter, Depends + +from app.api.deps import get_index +from app.core.logger_config import get_logger +from app.services.index import Index + +router = APIRouter() + +logger = get_logger(__name__) + + +@router.get("/search/{service_name}", status_code=200) +async def search_service(service_name: str, index: Index = Depends(get_index)): + response = await index.search_service(service_name) + return response + + +@router.get("/refresh_index", status_code=200) +async def refresh_index(index: Index = Depends(get_index)): + await index.load() + return {"status": "ok"} diff --git a/backend/df_designer/app/api/api_v1/endpoints/flows.py b/backend/df_designer/app/api/api_v1/endpoints/flows.py new file mode 100644 index 00000000..ef7d8654 --- /dev/null +++ b/backend/df_designer/app/api/api_v1/endpoints/flows.py @@ -0,0 +1,23 @@ +from fastapi import APIRouter +from omegaconf import OmegaConf + +from app.core.config import settings +from app.core.logger_config import get_logger +from app.db.base import read_conf, write_conf + +router = APIRouter() + +logger = get_logger(__name__) + + +@router.get("/") +async def flows_get(): + omega_flows = await read_conf(settings.frontend_flows_path) + dict_flows = OmegaConf.to_container(omega_flows, resolve=True) + return {"status": "ok", "data": dict_flows} + + +@router.post("/") +async def flows_post(flows: dict) -> dict[str, str]: + await write_conf(flows, settings.frontend_flows_path) + return {"status": "ok"} diff --git a/backend/df_designer/app/api/deps.py b/backend/df_designer/app/api/deps.py new file mode 100644 index 00000000..934e5cd9 --- /dev/null +++ b/backend/df_designer/app/api/deps.py @@ -0,0 +1,30 @@ +from app.services.index import Index +from app.services.process_manager import BuildManager, RunManager +from app.services.websocket_manager import WebSocketManager + +build_manager = BuildManager() + + +def get_build_manager() -> BuildManager: + return build_manager + + +run_manager = RunManager() + + +def get_run_manager() -> RunManager: + return run_manager + + +websocket_manager = WebSocketManager() + + +def get_websocket_manager() -> WebSocketManager: + return websocket_manager + + +index = Index() + + +def get_index() -> Index: + return index diff --git a/backend/df_designer/app/cli.py b/backend/df_designer/app/cli.py new file mode 100644 index 00000000..ef81411c --- /dev/null +++ b/backend/df_designer/app/cli.py @@ -0,0 +1,130 @@ +import asyncio +import json +import os +import sys +from pathlib import Path + +import typer +import uvicorn +from cookiecutter.main import cookiecutter + +from app.core.config import settings +from app.core.logger_config import get_logger +from app.services.json_translator import translator + +cli = typer.Typer() + + +async def _execute_command(command_to_run): + logger = get_logger(__name__) + try: + process = await asyncio.create_subprocess_exec(*command_to_run.split()) + + # Check the return code to determine success + if process.returncode == 0: + logger.info("Command '%s' executed successfully.", command_to_run) + elif process.returncode is None: + logger.info("Process by command '%s' is running.", command_to_run) + await process.wait() + logger.info("Process ended with return code: %d.", process.returncode) + sys.exit(process.returncode) + else: + logger.error("Command '%s' failed with return code: %d", command_to_run, process.returncode) + sys.exit(process.returncode) + + except Exception as e: + logger.error("Error executing '%s': %s", command_to_run, str(e)) + sys.exit(1) + + +def _execute_command_file(build_id: int, project_dir: str, command_file: str, preset: str): + logger = get_logger(__name__) + presets_build_path = Path(project_dir) / "df_designer" / "presets" / command_file + with open(presets_build_path) as file: + presets_build_file = json.load(file) + + if preset in presets_build_file: + command_to_run = presets_build_file[preset]["cmd"] + if preset == "success": + command_to_run += f" {build_id} --call_from_open_event_loop True" + logger.debug("Executing command for preset '%s': %s", preset, command_to_run) + + asyncio.run(_execute_command(command_to_run)) + else: + raise ValueError(f"Invalid preset '{preset}'. Preset must be one of {list(presets_build_file.keys())}") + + +@cli.command("build_bot") +def build_bot(build_id: int, project_dir: str = settings.work_directory, preset: str = "success"): + _execute_command_file(build_id, project_dir, "build.json", preset) + + +@cli.command("build_scenario") +def build_scenario(build_id: int, project_dir: str = ".", call_from_open_event_loop: bool = False): + if call_from_open_event_loop: + loop = asyncio.get_event_loop() + loop.create_task(translator(build_id=build_id, project_dir=project_dir)) + loop.run_until_complete(asyncio.wait([], return_when=asyncio.FIRST_COMPLETED)) + else: + asyncio.run(translator(build_id=build_id, project_dir=project_dir)) + + +@cli.command("run_bot") +def run_bot(build_id: int, project_dir: str = settings.work_directory, preset: str = "success"): + _execute_command_file(build_id, project_dir, "run.json", preset) + + +@cli.command("run_scenario") +def run_scenario(build_id: int, project_dir: str = ".", call_from_open_event_loop: bool = False): + script_path = Path(project_dir) / "bot" / "scripts" / f"build_{build_id}.yaml" + if not script_path.exists(): + raise FileNotFoundError(f"File {script_path} doesn't exist") + command_to_run = f"poetry run python {project_dir}/app.py --script-path {script_path}" + if call_from_open_event_loop: + loop = asyncio.get_event_loop() + loop.create_task(_execute_command(command_to_run)) + loop.run_until_complete(asyncio.wait([], return_when=asyncio.FIRST_COMPLETED)) + else: + asyncio.run(_execute_command(command_to_run)) + + +async def _run_server() -> None: + """Run the server.""" + await settings.server.run() + + +@cli.command("run_backend") +def run_backend( + ip_address: str = settings.host, + port: int = settings.backend_port, + conf_reload: str = str(settings.conf_reload), + project_dir: str = settings.work_directory, +) -> None: + """Run the backend.""" + settings.host = ip_address + settings.backend_port = port + settings.conf_reload = conf_reload.lower() in ["true", "yes", "t", "y", "1"] + settings.work_directory = project_dir + settings.uvicorn_config = uvicorn.Config( + settings.APP, + settings.host, + settings.backend_port, + reload=settings.conf_reload, + reload_dirs=str(settings.work_directory), + ) + settings.server = uvicorn.Server(settings.uvicorn_config) + settings.server.run() + + +@cli.command("init") +def init(destination: str = settings.work_directory, no_input: bool = False, overwrite_if_exists: bool = True): + original_dir = os.getcwd() + try: + os.chdir(destination) + cookiecutter( + "https://github.com/Ramimashkouk/df_d_template.git", + no_input=no_input, + overwrite_if_exists=overwrite_if_exists, + ) + finally: + os.chdir(original_dir) diff --git a/backend/df_designer/app/clients/__init__.py b/backend/df_designer/app/clients/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/clients/dff.py b/backend/df_designer/app/clients/dff.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/core/__init__.py b/backend/df_designer/app/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/core/auth.py b/backend/df_designer/app/core/auth.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/core/config.py b/backend/df_designer/app/core/config.py new file mode 100644 index 00000000..dd2be431 --- /dev/null +++ b/backend/df_designer/app/core/config.py @@ -0,0 +1,35 @@ +from pathlib import Path + +import uvicorn +from pydantic_settings import BaseSettings + + +class Settings(BaseSettings): + API_V1_STR: str = "/api/v1" + APP: str = "app.main:app" + + work_directory: str = "." + config_file_path: Path = Path(__file__).absolute() + static_files: Path = config_file_path.parent.with_name("static") + start_page: Path = static_files.joinpath("index.html") + package_dir: Path = config_file_path.parents[3] + + host: str = "0.0.0.0" + backend_port: int = 8000 + ui_port: int = 3000 + log_level: str = "debug" + conf_reload: bool = True # Enable auto-reload for development mode + + builds_path: Path = Path(f"{work_directory}/df_designer/builds.yaml") + runs_path: Path = Path(f"{work_directory}/df_designer/runs.yaml") + dir_logs: Path = Path(f"{work_directory}/df_designer/logs") + frontend_flows_path: Path = Path(f"{work_directory}/df_designer/frontend_flows.yaml") + index_path: Path = Path(f"{work_directory}/bot/custom/.services_index.yaml") + + uvicorn_config: uvicorn.Config = uvicorn.Config( + APP, host, backend_port, log_level=log_level, reload=conf_reload, reload_dirs=[work_directory, str(package_dir)] + ) + server: uvicorn.Server = uvicorn.Server(uvicorn_config) + + +settings = Settings() diff --git a/backend/df_designer/app/core/logger_config.py b/backend/df_designer/app/core/logger_config.py new file mode 100644 index 00000000..ae081e9a --- /dev/null +++ b/backend/df_designer/app/core/logger_config.py @@ -0,0 +1,58 @@ +import logging +from datetime import datetime +from pathlib import Path +from typing import Optional, Literal + +from app.core.config import settings + +LOG_LEVELS: dict[str, int] = { + "critical": logging.CRITICAL, + "error": logging.ERROR, + "warning": logging.WARNING, + "info": logging.INFO, + "debug": logging.DEBUG, +} + + +def setup_logging(log_type: Literal["builds", "runs"], id_: int, timestamp: datetime) -> Path: + # Ensure log_type is either 'builds' or 'runs' + if log_type not in ["builds", "runs"]: + raise ValueError("log_type must be 'builds' or 'runs'") + + # Get today's date separated with '_' using the timestamp + log_name = "_".join([str(id_), timestamp.strftime("%H:%M:%S")]) + today_date = timestamp.strftime("%Y%m%d") + + log_directory = settings.dir_logs / log_type / today_date + + log_directory.mkdir(parents=True, exist_ok=True) + + log_file = log_directory / f"{log_name}.log" + log_file.touch(exist_ok=True) + return log_file + + +def get_logger(name, file_handler_path: Optional[Path] = None): + if file_handler_path is None: + file_handler_path = settings.dir_logs / "logs.log" + file_handler_path.parent.mkdir(parents=True, exist_ok=True) + file_handler_path.touch(exist_ok=True) + + logger = logging.getLogger(name) + logger.propagate = False + logger.setLevel(LOG_LEVELS[settings.log_level]) + + c_handler = logging.StreamHandler() + f_handler = logging.FileHandler(file_handler_path) + c_handler.setLevel(LOG_LEVELS[settings.log_level]) + f_handler.setLevel(LOG_LEVELS[settings.log_level]) + + c_format = logging.Formatter("%(name)s - %(levelname)s - %(message)s") + f_format = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") + c_handler.setFormatter(c_format) + f_handler.setFormatter(f_format) + + logger.addHandler(c_handler) + logger.addHandler(f_handler) + + return logger diff --git a/backend/df_designer/app/core/security.py b/backend/df_designer/app/core/security.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/db/__init__.py b/backend/df_designer/app/db/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/db/base.py b/backend/df_designer/app/db/base.py new file mode 100644 index 00000000..9328ce5c --- /dev/null +++ b/backend/df_designer/app/db/base.py @@ -0,0 +1,29 @@ +from asyncio import Lock +from pathlib import Path +from typing import Union + +import aiofiles +from omegaconf import OmegaConf + +file_lock = Lock() + + +async def read_conf(path: Path): + async with file_lock: + async with aiofiles.open(path, "r", encoding="UTF-8") as file: + data = await file.read() + omega_data = OmegaConf.create(data) # read from a YAML string + return omega_data + + +async def write_conf(data: Union[list, dict], path: Path): + yaml_conf = OmegaConf.to_yaml(data) + async with file_lock: + async with aiofiles.open(path, "w", encoding="UTF-8") as file: # TODO: change to "a" for append + await file.write(yaml_conf) + + +async def read_logs(log_file: Path): + async with aiofiles.open(log_file, "r", encoding="UTF-8") as file: + logs = [line async for line in file] + return logs diff --git a/backend/df_designer/app/db/base_class.py b/backend/df_designer/app/db/base_class.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/db/crud/__init__.py b/backend/df_designer/app/db/crud/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/db/crud/base.py b/backend/df_designer/app/db/crud/base.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/db/crud/crud_bot.py b/backend/df_designer/app/db/crud/crud_bot.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/db/init_db.py b/backend/df_designer/app/db/init_db.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/db/models/__init__.py b/backend/df_designer/app/db/models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/db/models/bot.py b/backend/df_designer/app/db/models/bot.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/db/session.py b/backend/df_designer/app/db/session.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/initial_data.py b/backend/df_designer/app/initial_data.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/main.py b/backend/df_designer/app/main.py new file mode 100644 index 00000000..d05b93b0 --- /dev/null +++ b/backend/df_designer/app/main.py @@ -0,0 +1,52 @@ +from contextlib import asynccontextmanager + +from fastapi import APIRouter, FastAPI, Response +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse + +from app.api.api_v1.api import api_router +from app.api.deps import get_index +from app.core.config import settings + +index_dict = {} + + +@asynccontextmanager +async def lifespan(app: FastAPI): + index_dict["instance"] = get_index() + await index_dict["instance"].load() + yield + # Clean up and release the resources + + +app = FastAPI(title="DF Designer", lifespan=lifespan) + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +root_router = APIRouter() + + +@root_router.get("/app/{path:path}") +async def route_static_file(path: str): + if not settings.start_page.exists(): + return HTMLResponse(content="frontend is not built") + file_path = settings.static_files / path.split("/")[-1] + if file_path.suffix in (".js", ".css", ".html"): + return FileResponse(file_path) + return FileResponse(settings.static_files / "index.html") + + +@root_router.get("/") +async def root() -> Response: + """Redirect '/' to index.html""" + return RedirectResponse(url="/app") + + +app.include_router(root_router) +app.include_router(api_router) diff --git a/backend/df_designer/app/schemas/__init__.py b/backend/df_designer/app/schemas/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/schemas/pagination.py b/backend/df_designer/app/schemas/pagination.py new file mode 100644 index 00000000..bb089274 --- /dev/null +++ b/backend/df_designer/app/schemas/pagination.py @@ -0,0 +1,10 @@ +from fastapi import Query +from pydantic import BaseModel + + +class Pagination(BaseModel): + page: int = Query(1, gt=0) + limit: int = Query(10**5, gt=0) + + def offset(self) -> int: + return (self.page - 1) * self.limit diff --git a/backend/df_designer/app/schemas/preset.py b/backend/df_designer/app/schemas/preset.py new file mode 100644 index 00000000..0efb5b66 --- /dev/null +++ b/backend/df_designer/app/schemas/preset.py @@ -0,0 +1,8 @@ +from typing import Literal + +from pydantic import BaseModel + + +class Preset(BaseModel): + wait_time: float + end_status: Literal["success", "failure", "loop"] diff --git a/backend/df_designer/app/schemas/process_status.py b/backend/df_designer/app/schemas/process_status.py new file mode 100644 index 00000000..5a293dca --- /dev/null +++ b/backend/df_designer/app/schemas/process_status.py @@ -0,0 +1,11 @@ +from enum import Enum + + +class Status(Enum): + NULL = "null" + STOPPED = "stopped" + COMPLETED = "completed" + FAILED = "failed" + RUNNING = "running" + ALIVE = "alive" + FAILED_WITH_UNEXPECTED_CODE = "failed with unexpected returncode" diff --git a/backend/df_designer/app/services/__init__.py b/backend/df_designer/app/services/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/services/index.py b/backend/df_designer/app/services/index.py new file mode 100644 index 00000000..6b36ef00 --- /dev/null +++ b/backend/df_designer/app/services/index.py @@ -0,0 +1,102 @@ +import asyncio +from typing import List + +from omegaconf import OmegaConf + +from app.core.config import settings +from app.core.logger_config import get_logger +from app.db.base import read_conf, read_logs, write_conf + + +class Index: + def __init__(self): + self.path = settings.index_path + self.index = {} + self.conditions = [] + self.responses = [] + self.services = [] + self.logger = get_logger(__name__) + + async def _load_index(self): + db_index = await read_conf(self.path) + index_dict = OmegaConf.to_container(db_index, resolve=True) + self.index = index_dict + self.logger.debug("Index loaded") + + async def _load_conditions(self): + if (path := self.path.parent / "conditions.py").exists(): + self.conditions = await read_logs(path) + self.logger.debug("Conditions loaded") + else: + self.logger.warning("No conditions file found") + + async def _load_responses(self): + if (path := self.path.parent / "responses.py").exists(): + self.responses = await read_logs(path) + self.logger.debug("Responses loaded") + else: + self.logger.warning("No responses file found") + + async def _load_services(self): + if (path := self.path.parent / "services.py").exists(): + self.services = await read_logs(path) + self.logger.debug("Services loaded") + else: + self.logger.warning("No services file found") + + def _get_service(self, services_lst: list, lineno: int): + service = [] + func_lines = services_lst[lineno - 1 :] + self.logger.debug("services_lst: %s", services_lst) + for func_lineno, func_line in enumerate(func_lines): + if func_line[:4] == "def " and func_lineno != 0: + break + service.append(func_line) # ?maybe with \n + return service + + async def load(self): + """load index and services into memory""" + if not self.path.exists(): + raise FileNotFoundError(f"File {self.path} doesn't exist") + + await asyncio.gather( + self._load_index(), + self._load_conditions(), + self._load_responses(), + self._load_services(), + ) + self.logger.info("Index and services loaded") + self.logger.debug("Loaded index: %s", self.index) + + def get_services(self): + return self.index + + async def search_service(self, service_name): + if service_name not in self.index: + return [] + type_ = self.index[service_name]["type"] + lineno = int(self.index[service_name]["lineno"]) + + if type_ == "condition": + return self._get_service(self.conditions, lineno) + elif type_ == "response": + return self._get_service(self.responses, lineno) + elif type_ == "service": + return self._get_service(self.services, lineno) + + async def indexit(self, service_name: str, type_, lineno): + self.logger.debug("Indexing '%s'", service_name) + await self.indexit_all([service_name], [type_], [lineno]) + self.logger.info("Indexed '%s'", service_name) + + async def indexit_all(self, services_names: List[str], types: List[str], linenos: List[int]): + if not self.path.exists(): + raise FileNotFoundError(f"File {self.path} doesn't exist") + + for service_name, type_, lineno in zip(services_names, types, linenos): + self.index[service_name] = { + "type": type_, # condition/response/service + "lineno": lineno, + } + + await write_conf(self.index, self.path) # ?to background tasks diff --git a/backend/df_designer/app/services/json_translator.py b/backend/df_designer/app/services/json_translator.py new file mode 100644 index 00000000..7e5b97ec --- /dev/null +++ b/backend/df_designer/app/services/json_translator.py @@ -0,0 +1,184 @@ +from pathlib import Path +from typing import Tuple + +from app.api.deps import get_index +from app.core.logger_config import get_logger +from app.db.base import read_conf, write_conf + +logger = get_logger(__name__) + + +def get_db_paths(build_id: int, project_dir: Path, custom_dir: str) -> Tuple[Path, Path, Path]: + frontend_graph_path = project_dir / "df_designer" / "frontend_flows.yaml" + custom_conditions_file = project_dir / "bot" / custom_dir / "conditions.py" + script_path = project_dir / "bot" / "scripts" / f"build_{build_id}.yaml" + + if not frontend_graph_path.exists(): + raise FileNotFoundError(f"File {frontend_graph_path} doesn't exist") + if not custom_conditions_file.exists(): + raise FileNotFoundError(f"File {custom_conditions_file} doesn't exist") + if not script_path.exists(): + script_path.parent.mkdir(parents=True, exist_ok=True) + script_path.touch() + + return frontend_graph_path, script_path, custom_conditions_file + + +def organize_graph_according_to_nodes(flow_graph, script): + nodes = {} + for flow in flow_graph["flows"]: + for node in flow.data.nodes: + if "flags" in node.data and "start" in node.data.flags: + if "start_label" in script["CONFIG"]: + raise ValueError("There are more than one start node in the flow") + script["CONFIG"]["start_label"] = [flow.name, node.data.name] + nodes[node.id] = {"info": node} + nodes[node.id]["flow"] = flow.name + nodes[node.id]["TRANSITIONS"] = [] + return nodes + + +def get_condition(nodes, edge): + try: + return next( + condition + for condition in nodes[edge.source]["info"].data.conditions + if condition["id"] == edge.sourceHandle + ) + except StopIteration: + return None + + +def write_conditions_to_file(conditions_lines, custom_conditions_file): + # TODO: make reading and writing conditions async + with open(custom_conditions_file, "w", encoding="UTF-8") as file: + for line in conditions_lines: + if line[-1:] != "\n": + line = "".join([line, "\n"]) + file.write(line) + + +def add_transitions(nodes, edge, condition): + nodes[edge.source]["TRANSITIONS"].append( + { + "lbl": [ + nodes[edge.target]["flow"], + nodes[edge.target]["info"].data.name, + condition.data.priority, + ], + "cnd": f"custom_dir.conditions.{condition.name}", + } + ) + + +def fill_nodes_into_script(nodes, script): + for _, node in nodes.items(): + if node["flow"] not in script: + script[node["flow"]] = {} + script[node["flow"]].update( + { + node["info"].data.name: { + "RESPONSE": {"dff.Message": {"text": node["info"].data.response}}, + "TRANSITIONS": node["TRANSITIONS"], + } + } + ) + + +def append_condition(condition, conditions_lines): + condition = "".join([condition.data.python.action + "\n\n"]) + logger.debug(f"Condition to append: {condition}") + logger.debug(f"conditions_lines before appending: {conditions_lines}") + all_lines = conditions_lines + condition.split("\n") + return all_lines + + +async def _shift_cnds_in_index(index, cnd_strt_lineno, diff_in_lines): + services = index.get_services() + for _, service in services.items(): + if service["type"] == "condition": + if service["lineno"] - 1 > cnd_strt_lineno: # -1 is here to convert from file numeration to list numeration + service["lineno"] += diff_in_lines + + await index.indexit_all( + [service_name for service_name, _ in services.items()], + [service["type"] for _, service in services.items()], + [service["lineno"] for _, service in services.items()], + ) + + +async def replace_condition(condition, conditions_lines, cnd_strt_lineno, index): + cnd_strt_lineno = cnd_strt_lineno - 1 # conversion from file numeration to list numeration + all_lines = conditions_lines.copy() + condition = "".join([condition.data.python.action + "\n\n"]) + new_cnd_lines = condition.split("\n") + + old_cnd_lines_num = 0 + for lineno, line in enumerate(all_lines[cnd_strt_lineno:]): + if line[:4] == "def " and lineno != 0: + break + old_cnd_lines_num += 1 + + next_func_location = cnd_strt_lineno + old_cnd_lines_num + + logger.debug("new_cnd_lines\n") + logger.debug(new_cnd_lines) + all_lines = all_lines[:cnd_strt_lineno] + new_cnd_lines + all_lines[next_func_location:] + + diff_in_lines = len(new_cnd_lines) - old_cnd_lines_num + logger.debug("diff_in_lines: %s", diff_in_lines) + logger.debug("cnd_strt_lineno: %s", cnd_strt_lineno) + + await _shift_cnds_in_index(index, cnd_strt_lineno, diff_in_lines) + return all_lines + + +async def translator(build_id: int, project_dir: str, custom_dir: str = "custom"): + index = get_index() + await index.load() + index.logger.debug("Loaded index '%s'", index.index) + + frontend_graph_path, script_path, custom_conditions_file = get_db_paths(build_id, Path(project_dir), custom_dir) + + script = { + "CONFIG": {"custom_dir": "/".join(["..", custom_dir])}, + } + flow_graph = await read_conf(frontend_graph_path) + + nodes = organize_graph_according_to_nodes(flow_graph, script) + + with open(custom_conditions_file, "r", encoding="UTF-8") as file: + conditions_lines = file.readlines() + + for flow in flow_graph["flows"]: + for edge in flow.data.edges: + if edge.source in nodes and edge.target in nodes: + condition = get_condition(nodes, edge) + if condition is None: + logger.error( + "A condition of edge '%s' - '%s' and id of '%s' is not found in the corresponding node", + edge.source, + edge.target, + edge.sourceHandle, + ) + continue + + if condition.name not in (cnd_names := index.index): + logger.debug("Adding condition: %s", condition.name) + cnd_lineno = len(conditions_lines) + conditions_lines = append_condition(condition, conditions_lines) + await index.indexit(condition.name, "condition", cnd_lineno + 1) + else: + logger.debug("Replacing condition: %s", condition.name) + conditions_lines = await replace_condition( + condition, conditions_lines, cnd_names[condition.name]["lineno"], index + ) + + add_transitions(nodes, edge, condition) + else: + logger.error("A node of edge '%s-%s' is not found in nodes", edge.source, edge.target) + + fill_nodes_into_script(nodes, script) + + write_conditions_to_file(conditions_lines, custom_conditions_file) + await write_conf(script, script_path) diff --git a/backend/df_designer/app/services/process.py b/backend/df_designer/app/services/process.py new file mode 100644 index 00000000..e5c2aa10 --- /dev/null +++ b/backend/df_designer/app/services/process.py @@ -0,0 +1,221 @@ +import asyncio +import logging +from abc import ABC, abstractmethod +from datetime import datetime +from pathlib import Path +from typing import List, Optional + +from app.core.config import settings +from app.core.logger_config import get_logger, setup_logging +from app.db.base import read_conf, write_conf +from app.schemas.process_status import Status + + +def _map_to_str(params: dict): + for k, v in params.items(): + if isinstance(v, datetime): + params[k] = v.strftime("%Y-%m-%dT%H:%M:%S") + elif isinstance(v, Path): + params[k] = str(v) + + +class Process(ABC): + def __init__(self, id_: int, preset_end_status=""): + self.id: int = id_ + self.preset_end_status: str = preset_end_status + self.status: Status = Status.NULL + self.timestamp: datetime = datetime.now() + self.log_path: Path + self.lock = asyncio.Lock() + self.process: asyncio.subprocess.Process # pylint: disable=no-member #TODO: is naming ok? + self.logger: logging.Logger + + async def start(self, cmd_to_run): + self.process = await asyncio.create_subprocess_exec( + *cmd_to_run.split(), + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + stdin=asyncio.subprocess.PIPE, + ) + + async def get_full_info(self, attributes: list) -> dict: + await self.check_status() + info = {key: getattr(self, key) for key in self.__dict__ if key in attributes} + if "status" in attributes: + info["status"] = self.status.value + + return info + + @abstractmethod + async def update_db_info(self): + raise NotImplementedError + + async def periodically_check_status(self): + while True: + await self.update_db_info() # check status and update db + self.logger.info("Status of process '%s': %s", self.id, self.status) + if self.status in [Status.STOPPED, Status.COMPLETED, Status.FAILED]: + break + await asyncio.sleep(2) # TODO: ?sleep time shouldn't be constant + + async def check_status(self) -> Status: + """Returns the process status. + - Status.NULL: When a process is initiated but not started yet. This condition is unusual and typically + indicates incorrect usage or a process misuse in backend logic. + - Status.ALIVE: process is alive and ready to communicate + - Status.RUNNING: process is still trying to get alive. no communication + - Status.COMPLETED: returncode is 0 + - Status.FAILED: returncode is 1 + - Status.STOPPED: returncode is -15 + - Status.FAILED_WITH_UNEXPECTED_CODE: failed with other returncode + """ + if self.process is None: + self.status = Status.NULL + # if process is already alive, don't interrupt potential open channels by checking status periodically. + elif self.process.returncode is None: + if self.status == Status.ALIVE: + self.status = Status.ALIVE + else: + if await self.is_alive(): + self.status = Status.ALIVE + else: + self.status = Status.RUNNING + + elif self.process.returncode == 0: + self.status = Status.COMPLETED + elif self.process.returncode == 1: + self.status = Status.FAILED + elif self.process.returncode == -15: + self.status = Status.STOPPED + else: + self.logger.error( + "Unexpected code was returned: '%s'. A non-zero return code indicates an error.", + self.process.returncode, + ) + self.status = Status.FAILED_WITH_UNEXPECTED_CODE + + if self.status not in [Status.NULL, Status.RUNNING, Status.ALIVE, Status.STOPPED]: + stdout, stderr = await self.process.communicate() + if stdout: + self.logger.info(f"[stdout]\n{stdout.decode()}") + if stderr: + self.logger.error(f"[stderr]\n{stderr.decode()}") + + return self.status + + async def stop(self): + if self.process is None: # Check if a process has been started + self.logger.error("Cannot stop a process '%s' that has not started yet.", self.id) + raise RuntimeError + try: + self.logger.debug("Terminating process '%s'", self.id) + self.process.terminate() + await self.process.wait() + self.logger.debug("Process returencode '%s' ", self.process.returncode) + + except ProcessLookupError as exc: + self.logger.error("Process '%s' not found. It may have already exited.", self.id) + raise ProcessLookupError from exc + + async def read_stdout(self): + async with self.lock: + if self.process is None: + self.logger.error("Cannot read stdout from a process '%s' that has not started yet.", self.id) + raise RuntimeError + + return await self.process.stdout.readline() + + async def write_stdin(self, message): + if self.process is None: + self.logger.error("Cannot write into stdin of a process '%s' that has not started yet.", self.id) + raise RuntimeError + self.process.stdin.write(message) + await self.process.stdin.drain() + + async def is_alive(self) -> bool: + timeout = 0.5 + message = b"Hi\n" + try: + # Attempt to write and read from the process with a timeout. + await self.write_stdin(message) + output = await asyncio.wait_for(self.read_stdout(), timeout=timeout) + if not output: + return False + self.logger.debug("Process output afer communication: %s", output.decode()) + return True + except asyncio.exceptions.TimeoutError: + self.logger.debug("Process did not accept input within the timeout period.") + return False + + +class RunProcess(Process): + def __init__(self, id_: int, build_id: int = None, preset_end_status: str = ""): + super().__init__(id_, preset_end_status) + self.build_id: int = build_id + + self.log_path: Path = setup_logging("runs", self.id, self.timestamp) + self.logger = get_logger(str(id_), self.log_path) + + async def get_full_info(self, attributes: Optional[list] = None) -> dict: + if attributes is None: + attributes = ["id", "preset_end_status", "status", "timestamp", "log_path", "build_id"] + return await super().get_full_info(attributes) + + async def update_db_info(self): + # save current run info into runs_path + self.logger.info("Updating db run info") + runs_conf = await read_conf(settings.runs_path) + + run_params = await self.get_full_info() + _map_to_str(run_params) + + for run in runs_conf: + if run.id == run_params["id"]: + for key, value in run_params.items(): + setattr(run, key, value) + break + else: + runs_conf.append(run_params) + + await write_conf(runs_conf, settings.runs_path) + + # save current run id into the correspoinding build in builds_path + builds_conf = await read_conf(settings.builds_path) + for build in builds_conf: + if build.id == run_params["build_id"]: + if run_params["id"] not in build.run_ids: + build.run_ids.append(run_params["id"]) + break + + await write_conf(builds_conf, settings.builds_path) + + +class BuildProcess(Process): + def __init__(self, id_: int, preset_end_status: str = ""): + super().__init__(id_, preset_end_status) + self.run_ids: List[int] = [] + + self.log_path: Path = setup_logging("builds", self.id, self.timestamp) + self.logger = get_logger(str(id_), self.log_path) + + async def get_full_info(self, attributes: Optional[list] = None) -> dict: + if attributes is None: + attributes = ["id", "preset_end_status", "status", "timestamp", "log_path", "run_ids"] + return await super().get_full_info(attributes) + + async def update_db_info(self): + # save current build info into builds_path + builds_conf = await read_conf(settings.builds_path) + + build_params = await self.get_full_info() + _map_to_str(build_params) + + for build in builds_conf: + if build.id == build_params["id"]: + for key, value in build_params.items(): + setattr(build, key, value) + break + else: + builds_conf.append(build_params) + + await write_conf(builds_conf, settings.builds_path) diff --git a/backend/df_designer/app/services/process_manager.py b/backend/df_designer/app/services/process_manager.py new file mode 100644 index 00000000..d876f820 --- /dev/null +++ b/backend/df_designer/app/services/process_manager.py @@ -0,0 +1,132 @@ +from pathlib import Path +from typing import List + +from omegaconf import OmegaConf + +from app.core.config import settings +from app.core.logger_config import get_logger +from app.db.base import read_conf, read_logs +from app.schemas.preset import Preset +from app.services.process import BuildProcess, RunProcess + +logger = get_logger(__name__) + + +class ProcessManager: + def __init__(self): + self.processes = {} + self.last_id: int + + def get_last_id(self): + return self.last_id + + async def stop(self, id_): + if id_ not in self.processes: + logger.error("Process with id '%s' not found in recent running processes", id_) + raise ProcessLookupError + try: + await self.processes[id_].stop() + except (RuntimeError, ProcessLookupError): + raise + + async def check_status(self, id_): + await self.processes[id_].periodically_check_status() + + async def get_status(self, id_): + return await self.processes[id_].check_status() + + async def get_process_info(self, id_: int, path: Path): + db_conf = await read_conf(path) + conf_dict = OmegaConf.to_container(db_conf, resolve=True) + return next((db_process for db_process in conf_dict if db_process["id"] == id_), None) + + async def get_full_info(self, offset: int, limit: int, path: Path) -> List[dict]: + db_conf = await read_conf(path) + conf_dict = OmegaConf.to_container(db_conf, resolve=True) + return conf_dict[offset : offset + limit] + + async def fetch_process_logs(self, id_: int, offset: int, limit: int, path: Path): + process_info = await self.get_process_info(id_, path) + if process_info is None: + logger.error("Id '%s' not found", id_) + return None + + log_file = process_info["log_path"] + try: + logs = await read_logs(log_file) + logs = [log for log in logs if log.strip()] + except FileNotFoundError: + logger.error("Log file '%s' not found", log_file) + return None + + if offset > len(logs): + logger.info("Offset '%s' is out of bounds ('%s' logs found)", offset, len(logs)) + return None # TODO: raise error! + + logger.info("Returning %s logs", len(logs)) + return logs[offset : offset + limit] + + +class RunManager(ProcessManager): + def __init__(self): + super().__init__() + + async def start(self, build_id: int, preset: Preset): + cmd_to_run = f"dflowd run_bot {build_id} --preset {preset.end_status}" + self.last_id = max([run["id"] for run in await self.get_full_info(0, 10000)]) + self.last_id += 1 + id_ = self.last_id + process = RunProcess(id_, build_id, preset.end_status) + await process.start(cmd_to_run) + process.logger.debug("Started process. status: '%s'", process.process.returncode) + self.processes[id_] = process + + return self.last_id + + async def get_run_info(self, id_: int): + return await super().get_process_info(id_, settings.runs_path) + + async def get_full_info(self, offset: int, limit: int, path: Path = settings.runs_path): + return await super().get_full_info(offset, limit, path) + + async def fetch_run_logs(self, run_id: int, offset: int, limit: int): + return await self.fetch_process_logs(run_id, offset, limit, settings.runs_path) + + +class BuildManager(ProcessManager): + def __init__(self): + super().__init__() + + async def start(self, preset: Preset): + self.last_id = max([build["id"] for build in await self.get_full_info(0, 10000)]) + self.last_id += 1 + id_ = self.last_id + process = BuildProcess(id_, preset.end_status) + cmd_to_run = f"dflowd build_bot {id_} --preset {preset.end_status}" + await process.start(cmd_to_run) + self.processes[id_] = process + + return self.last_id + + async def get_build_info(self, id_: int, run_manager): + builds_info = await self.get_full_info_with_runs_info(run_manager, offset=0, limit=10**5) + return next((build for build in builds_info if build["id"] == id_), None) + + async def get_full_info(self, offset: int, limit: int, path: Path = settings.builds_path): + return await super().get_full_info(offset, limit, path) + + async def get_full_info_with_runs_info(self, run_manager, offset: int, limit: int): + builds_info = await self.get_full_info(offset=offset, limit=limit) + runs_info = await run_manager.get_full_info(offset=0, limit=10**5) + for build in builds_info: + del build["run_ids"] + build["runs"] = [] + for run in runs_info: + if build["id"] == run["build_id"]: + run_without_build_id = {k: v for k, v in run.items() if k != "build_id"} + build["runs"].append(run_without_build_id) + + return builds_info + + async def fetch_build_logs(self, build_id: int, offset: int, limit: int): + return await self.fetch_process_logs(build_id, offset, limit, settings.builds_path) diff --git a/backend/df_designer/app/services/websocket_manager.py b/backend/df_designer/app/services/websocket_manager.py new file mode 100644 index 00000000..ab0a03ad --- /dev/null +++ b/backend/df_designer/app/services/websocket_manager.py @@ -0,0 +1,65 @@ +import asyncio +from asyncio.tasks import Task +from typing import Dict, Set + +from fastapi import WebSocket, WebSocketDisconnect + +from app.core.logger_config import get_logger +from app.services.process_manager import ProcessManager + +logger = get_logger(__name__) + + +class WebSocketManager: + def __init__(self): + self.pending_tasks: Dict[WebSocket, Set[Task]] = dict() + self.active_connections: list[WebSocket] = [] + + async def connect(self, websocket: WebSocket): + await websocket.accept() + self.active_connections.append(websocket) + + def disconnect(self, websocket: WebSocket): + # TODO: await websocket.close() + if websocket in self.pending_tasks: + logger.info("Cancelling pending tasks") + for task in self.pending_tasks[websocket]: + task.cancel() + del self.pending_tasks[websocket] + self.active_connections.remove(websocket) + + def check_status(self, websocket: WebSocket): + if websocket in self.active_connections: + return websocket # return Status! + + async def send_process_output_to_websocket( + self, run_id: int, process_manager: ProcessManager, websocket: WebSocket + ): + """Read and forward process output to the websocket client.""" + try: + while True: + response = await process_manager.processes[run_id].read_stdout() + if not response: + break + await websocket.send_text(response.decode().strip()) + except WebSocketDisconnect: + logger.info("Websocket connection is closed by client") + except RuntimeError: + raise + + async def forward_websocket_messages_to_process( + self, run_id: int, process_manager: ProcessManager, websocket: WebSocket + ): + """Listen for messages from the websocket and send them to the subprocess.""" + try: + while True: + user_message = await websocket.receive_text() + if not user_message: + break + await process_manager.processes[run_id].write_stdin(user_message.encode() + b"\n") + except asyncio.CancelledError: + logger.info("Websocket connection is closed") + except WebSocketDisconnect: + logger.info("Websocket connection is closed by client") + except RuntimeError: + raise diff --git a/backend/df_designer/app/static/.gitkeep b/backend/df_designer/app/static/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/tests/__init__.py b/backend/df_designer/app/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/tests/api/__init__.py b/backend/df_designer/app/tests/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/tests/api/test_bot.py b/backend/df_designer/app/tests/api/test_bot.py new file mode 100644 index 00000000..cc49de0a --- /dev/null +++ b/backend/df_designer/app/tests/api/test_bot.py @@ -0,0 +1,172 @@ +import pytest +from fastapi import BackgroundTasks, HTTPException, WebSocket + +from app.api.api_v1.endpoints.bot import ( + _check_process_status, + _stop_process, + check_build_processes, + check_run_processes, + connect, + get_build_logs, + get_run_logs, + start_build, + start_run, +) +from app.schemas.process_status import Status +from app.services.process import RunProcess +from app.services.process_manager import BuildManager, RunManager +from app.services.websocket_manager import WebSocketManager + +PROCESS_ID = 0 +RUN_ID = 42 +BUILD_ID = 43 + + +@pytest.mark.parametrize("process_type, process_manager", [("build", BuildManager), ("run", RunManager)]) +@pytest.mark.asyncio +async def test_stop_process_success(mocker, process_type, process_manager): + mock_stop = mocker.AsyncMock() + mocker.patch.object(process_manager, "stop", mock_stop) + + # Call the function under test + await _stop_process(PROCESS_ID, process_manager(), process_type) + + # Assert the stop method was called once with the correct id + mock_stop.assert_awaited_once_with(PROCESS_ID) + + +# TODO: take into consideration the errors when process type is build +@pytest.mark.parametrize("error_type", [RuntimeError, ProcessLookupError]) +@pytest.mark.asyncio +async def test_stop_process_error(mocker, error_type): + mock_stop = mocker.AsyncMock(side_effect=error_type) + mocker.patch.object(RunManager, "stop", mock_stop) + + process_type = "run" + + with pytest.raises(HTTPException) as exc_info: + await _stop_process(PROCESS_ID, RunManager(), process_type) + + # Assert the stop method was called once with the correct id + assert exc_info.value.status_code == 404 + mock_stop.assert_awaited_once_with(PROCESS_ID) + + +# TODO: check the errors +@pytest.mark.asyncio +async def test_check_process_status(mocker): + mocked_process_manager = mocker.MagicMock() + mocker.patch.object(mocked_process_manager, "processes", {PROCESS_ID: mocker.MagicMock()}) + mocker.patch.object(mocked_process_manager, "get_status", mocker.AsyncMock(return_value=Status.ALIVE)) + + response = await _check_process_status(PROCESS_ID, mocked_process_manager) + + assert response == {"status": "alive"} + mocked_process_manager.get_status.assert_awaited_once_with(0) + + +@pytest.mark.asyncio +async def test_start_build(mocker): + build_manager = mocker.MagicMock() + preset = mocker.MagicMock() + + start = mocker.AsyncMock(return_value=BUILD_ID) + mocker.patch.multiple(build_manager, start=start, check_status=mocker.AsyncMock()) + mocker.patch.multiple(preset, wait_time=0, end_status="loop") + + response = await start_build(preset, background_tasks=BackgroundTasks(), build_manager=build_manager) + start.assert_awaited_once_with(preset) + assert response == {"status": "ok", "build_id": BUILD_ID} + + +@pytest.mark.asyncio +async def test_check_build_processes_some_info(mocker, pagination): + build_manager = mocker.MagicMock(spec=BuildManager()) + run_manager = mocker.MagicMock(spec=RunManager()) + + await check_build_processes(BUILD_ID, build_manager, run_manager, pagination) + + build_manager.get_build_info.assert_awaited_once_with(BUILD_ID, run_manager) + + +@pytest.mark.asyncio +async def test_check_build_processes_all_info(mocker, pagination): + build_id = None + build_manager = mocker.MagicMock(spec=BuildManager()) + run_manager = mocker.MagicMock(spec=RunManager()) + + await check_build_processes(build_id, build_manager, run_manager, pagination) + + build_manager.get_full_info_with_runs_info.assert_awaited_once_with( + run_manager, offset=pagination.offset(), limit=pagination.limit + ) + + +@pytest.mark.asyncio +async def test_get_build_logs(mocker, pagination): + build_manager = mocker.MagicMock(spec=BuildManager()) + + await get_build_logs(BUILD_ID, build_manager, pagination) + + build_manager.fetch_build_logs.assert_awaited_once_with(BUILD_ID, pagination.offset(), pagination.limit) + + +@pytest.mark.asyncio +async def test_start_run(mocker): + run_manager = mocker.MagicMock() + preset = mocker.MagicMock() + + start = mocker.AsyncMock(return_value=RUN_ID) + mocker.patch.multiple(run_manager, start=start, check_status=mocker.AsyncMock()) + mocker.patch.multiple(preset, wait_time=0, end_status="loop") + + response = await start_run( + build_id=BUILD_ID, preset=preset, background_tasks=BackgroundTasks(), run_manager=run_manager + ) + start.assert_awaited_once_with(BUILD_ID, preset) + assert response == {"status": "ok", "run_id": RUN_ID} + + +@pytest.mark.asyncio +async def test_check_run_processes_some_info(mocker, pagination): + run_manager = mocker.MagicMock(spec=RunManager()) + + await check_run_processes(RUN_ID, run_manager, pagination) + + run_manager.get_run_info.assert_awaited_once_with(RUN_ID) + + +@pytest.mark.asyncio +async def test_check_run_processes_all_info(mocker, pagination): + run_id = None + run_manager = mocker.MagicMock(spec=RunManager()) + + await check_run_processes(run_id, run_manager, pagination) + + run_manager.get_full_info.assert_awaited_once_with(offset=pagination.offset(), limit=pagination.limit) + + +@pytest.mark.asyncio +async def test_get_run_logs(mocker, pagination): + run_manager = mocker.MagicMock(spec=RunManager()) + + await get_run_logs(RUN_ID, run_manager, pagination) + + run_manager.fetch_run_logs.assert_awaited_once_with(RUN_ID, pagination.offset(), pagination.limit) + + +@pytest.mark.asyncio +async def test_connect(mocker): + websocket = mocker.MagicMock(spec=WebSocket) + websocket_manager = mocker.MagicMock(spec=WebSocketManager()) + run_manager = mocker.MagicMock(spec=RunManager()) + run_process = mocker.MagicMock(spec=RunProcess(RUN_ID)) + run_manager.processes = {RUN_ID: run_process} + mocker.patch.object(websocket, "query_params", {"run_id": str(RUN_ID)}) + + await connect(websocket, websocket_manager, run_manager) + + websocket_manager.connect.assert_awaited_once_with(websocket) + websocket_manager.send_process_output_to_websocket.assert_awaited_once_with(RUN_ID, run_manager, websocket) + websocket_manager.forward_websocket_messages_to_process.assert_awaited_once_with(RUN_ID, run_manager, websocket) + websocket_manager.disconnect.assert_called_once_with(websocket) diff --git a/backend/df_designer/app/tests/api/test_flows.py b/backend/df_designer/app/tests/api/test_flows.py new file mode 100644 index 00000000..ba4ada64 --- /dev/null +++ b/backend/df_designer/app/tests/api/test_flows.py @@ -0,0 +1,20 @@ +# create test flows function here +import pytest +from omegaconf import OmegaConf + +from app.api.api_v1.endpoints.flows import flows_get, flows_post + + +@pytest.mark.asyncio +async def test_flows_get(mocker): + mocker.patch("app.api.api_v1.endpoints.flows.read_conf", return_value=OmegaConf.create({"foo": "bar"})) + response = await flows_get() + assert response["status"] == "ok" + assert response["data"] == {"foo": "bar"} + + +@pytest.mark.asyncio +async def test_flows_post(mocker): + mocker.patch("app.api.api_v1.endpoints.flows.write_conf", return_value={}) + response = await flows_post({"foo": "bar"}) + assert response["status"] == "ok" diff --git a/backend/df_designer/app/tests/conftest.py b/backend/df_designer/app/tests/conftest.py new file mode 100644 index 00000000..7e316834 --- /dev/null +++ b/backend/df_designer/app/tests/conftest.py @@ -0,0 +1,79 @@ +from contextlib import asynccontextmanager +from typing import Generator + +import httpx +import pytest +from fastapi.testclient import TestClient +from httpx import AsyncClient + +from app.main import app +from app.schemas.pagination import Pagination +from app.schemas.preset import Preset +from app.services.process import RunProcess +from app.services.process_manager import BuildManager, RunManager +from app.services.websocket_manager import WebSocketManager + + +async def start_process(async_client: AsyncClient, endpoint, preset_end_status) -> httpx.Response: + return await async_client.post( + endpoint, + json={"wait_time": 0.1, "end_status": preset_end_status}, + ) + + +@asynccontextmanager +async def override_dependency(mocker_obj, get_manager_func): + process_manager = get_manager_func() + process_manager.check_status = mocker_obj.AsyncMock() + app.dependency_overrides[get_manager_func] = lambda: process_manager + try: + yield process_manager + finally: + for _, process in process_manager.processes.items(): + if process.process.returncode is None: + await process.stop() + app.dependency_overrides = {} + + +@pytest.fixture +def client() -> Generator: + with TestClient(app=app) as client: + yield client + + +@pytest.fixture(scope="session") +def preset() -> Preset: + return Preset( + wait_time=0, + end_status="loop", + ) + + +@pytest.fixture +def pagination() -> Pagination: + return Pagination() + + +@pytest.fixture() +def run_process(): + async def _run_process(cmd_to_run): + process = RunProcess(id_=0) + await process.start(cmd_to_run) + return process + + return _run_process + + +@pytest.fixture() +def run_manager(): + return RunManager() + + +@pytest.fixture() +def build_manager(): + return BuildManager() + + +@pytest.fixture +def websocket_manager(): + return WebSocketManager() diff --git a/backend/df_designer/app/tests/e2e/__init__.py b/backend/df_designer/app/tests/e2e/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/tests/e2e/test_e2e.py b/backend/df_designer/app/tests/e2e/test_e2e.py new file mode 100644 index 00000000..88daf4ce --- /dev/null +++ b/backend/df_designer/app/tests/e2e/test_e2e.py @@ -0,0 +1,58 @@ +import asyncio + +import httpx +import pytest +from httpx_ws import aconnect_ws +from httpx_ws.transport import ASGIWebSocketTransport + +from app.api.deps import get_build_manager, get_run_manager +from app.core.logger_config import get_logger +from app.main import app +from app.schemas.process_status import Status +from app.tests.conftest import override_dependency, start_process + +logger = get_logger(__name__) + + +async def _assert_process_status(response, process_manager): + assert response.json().get("status") == "ok", "Start process response status is not 'ok'" + process_manager.check_status.assert_awaited_once() + + +@pytest.mark.asyncio +async def test_all(mocker): + async with httpx.AsyncClient(transport=ASGIWebSocketTransport(app)) as client: + async with override_dependency(mocker, get_build_manager) as process_manager: + response = await start_process( + client, + endpoint="http://localhost:8000/api/v1/bot/build/start", + preset_end_status="success", + ) + + build_id = process_manager.get_last_id() + + await _assert_process_status(response, process_manager) + try: + await asyncio.wait_for(process_manager.processes[build_id].process.wait(), timeout=20) + except asyncio.exceptions.TimeoutError as exc: + raise Exception( + "Process with expected end status Status.ALIVE timed out with status Status.RUNNING." + ) from exc + assert await process_manager.get_status(build_id) == Status.COMPLETED + + async with override_dependency(mocker, get_run_manager) as process_manager: + response = await start_process( + client, + endpoint=f"http://localhost:8000/api/v1/bot/run/start/{build_id}", + preset_end_status="success", + ) + + run_id = process_manager.get_last_id() + + await _assert_process_status(response, process_manager) + await asyncio.sleep(10) + assert await process_manager.get_status(run_id) == Status.ALIVE + + async with aconnect_ws(f"http://localhost:8000/api/v1/bot/run/connect?run_id={run_id}", client) as ws: + message = await ws.receive_text() + assert message == "Start chatting" diff --git a/backend/df_designer/app/tests/integration/__init__.py b/backend/df_designer/app/tests/integration/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/tests/integration/test_api_integration.py b/backend/df_designer/app/tests/integration/test_api_integration.py new file mode 100644 index 00000000..3ee9bbfe --- /dev/null +++ b/backend/df_designer/app/tests/integration/test_api_integration.py @@ -0,0 +1,161 @@ +import asyncio + +import httpx +import pytest +from httpx import ASGITransport, AsyncClient +from httpx_ws import aconnect_ws +from httpx_ws.transport import ASGIWebSocketTransport + +from app.api.deps import get_build_manager, get_run_manager +from app.core.logger_config import get_logger +from app.main import app +from app.schemas.process_status import Status +from app.tests.conftest import override_dependency, start_process + +logger = get_logger(__name__) + + +async def _assert_process_status(response, process_manager, expected_end_status): + assert response.json().get("status") == "ok", "Start process response status is not 'ok'" + process_manager.check_status.assert_awaited_once() + + try: + await asyncio.wait_for( + process_manager.processes[process_manager.last_id].process.wait(), timeout=10 + ) # TODO: Consider making this timeout configurable + except asyncio.exceptions.TimeoutError as exc: + if expected_end_status in [Status.ALIVE, Status.RUNNING]: + logger.debug("Loop process timed out. Expected behavior.") + else: + raise Exception( + f"Process with expected end status '{expected_end_status}' timed out with status 'running'." + ) from exc + + process_id = process_manager.last_id + logger.debug("Process id is %s", process_id) + current_status = await process_manager.get_status(process_id) + assert ( + current_status == expected_end_status + ), f"Current process status '{current_status}' did not match the expected '{expected_end_status}'" + + return current_status + + +async def _test_start_process(mocker_obj, get_manager_func, endpoint, preset_end_status, expected_end_status): + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as async_client: + async with override_dependency(mocker_obj, get_manager_func) as process_manager: + response = await start_process(async_client, endpoint, preset_end_status) + current_status = await _assert_process_status(response, process_manager, expected_end_status) + + if current_status == Status.RUNNING: + process_manager.processes[process_manager.last_id].process.terminate() + await process_manager.processes[process_manager.last_id].process.wait() + + +async def _test_stop_process(mocker, get_manager_func, start_endpoint, stop_endpoint): + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as async_client: + async with override_dependency(mocker, get_manager_func) as manager: + start_response = await start_process(async_client, start_endpoint, preset_end_status="loop") + assert start_response.status_code == 201 + logger.debug("Processes: %s", manager.processes) + + last_id = manager.get_last_id() + logger.debug("Last id: %s, type: %s", last_id, type(last_id)) + logger.debug("Process status %s", await manager.get_status(last_id)) + + stop_response = await async_client.get(f"{stop_endpoint}/{last_id}") + assert stop_response.status_code == 200 + assert stop_response.json() == {"status": "ok"} + + +# Test flows endpoints and interaction with db (read and write conf) +def test_flows(client): # noqa: F811 + get_response = client.get("/api/v1/flows") + assert get_response.status_code == 200 + data = get_response.json()["data"] + assert "flows" in data + + response = client.post("/api/v1/flows", json=data) + assert response.status_code == 200 + + +# def test_get_build_status(client): +# pass + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "end_status, process_status", [("failure", Status.FAILED), ("loop", Status.RUNNING), ("success", Status.COMPLETED)] +) +async def test_start_build(mocker, end_status, process_status): + await _test_start_process( + mocker, + get_build_manager, + endpoint="/api/v1/bot/build/start", + preset_end_status=end_status, + expected_end_status=process_status, + ) + + +@pytest.mark.asyncio +async def test_stop_build(mocker): + await _test_stop_process( + mocker, get_build_manager, start_endpoint="/api/v1/bot/build/start", stop_endpoint="/api/v1/bot/build/stop" + ) + + +# def test_get_run_status(client): +# pass + + +# Test processes of various end_status + Test integration with get_status. No db interaction (mocked processes) +@pytest.mark.asyncio +@pytest.mark.parametrize( + "end_status, process_status", [("failure", Status.FAILED), ("loop", Status.RUNNING), ("success", Status.ALIVE)] +) +async def test_start_run(mocker, end_status, process_status): + build_id = 43 + await _test_start_process( + mocker, + get_run_manager, + endpoint=f"/api/v1/bot/run/start/{build_id}", + preset_end_status=end_status, + expected_end_status=process_status, + ) + + +@pytest.mark.asyncio +async def test_stop_run(mocker): + build_id = 43 + await _test_stop_process( + mocker, + get_run_manager, + start_endpoint=f"/api/v1/bot/run/start/{build_id}", + stop_endpoint="/api/v1/bot/run/stop", + ) + + +@pytest.mark.asyncio +async def test_connect_to_ws(mocker): + build_id = 43 + + async with httpx.AsyncClient(transport=ASGIWebSocketTransport(app)) as client: + async with override_dependency(mocker, get_run_manager) as process_manager: + # Start a process + start_response = await start_process( + client, + endpoint=f"http://localhost:8000/api/v1/bot/run/start/{build_id}", + preset_end_status="success", + ) + assert start_response.status_code == 201 + process_manager.check_status.assert_awaited_once() + + run_id = process_manager.get_last_id() + logger.debug(f"run_id: {run_id}") + await asyncio.sleep(10) + + assert await process_manager.get_status(run_id) == Status.ALIVE + + async with aconnect_ws(f"http://localhost:8000/api/v1/bot/run/connect?run_id={run_id}", client) as ws: + message = await ws.receive_text() + assert message == "Start chatting" diff --git a/backend/df_designer/app/tests/services/__init__.py b/backend/df_designer/app/tests/services/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/tests/services/test_process.py b/backend/df_designer/app/tests/services/test_process.py new file mode 100644 index 00000000..e6bdd273 --- /dev/null +++ b/backend/df_designer/app/tests/services/test_process.py @@ -0,0 +1,55 @@ +import asyncio + +import pytest + +from app.core.logger_config import get_logger +from app.schemas.process_status import Status + +logger = get_logger(__name__) + + +class TestRunProcess: + # def test_update_db_info(self, run_process): + # process = await run_process("echo 'Hello df_designer'") + # process.update_db_info() + + @pytest.mark.asyncio + @pytest.mark.parametrize( + "cmd_to_run, status", + [ + ("sleep 10000", Status.RUNNING), + ("false", Status.FAILED), + ("echo Hello df_designer", Status.COMPLETED), + ], + ) + async def test_check_status(self, run_process, cmd_to_run, status): + process = await run_process(cmd_to_run) + await asyncio.sleep(2) + assert await process.check_status() == status + + # def test_periodically_check_status(self, run_process): + # process = await run_process("sleep 10000") + # run_process.periodically_check_status() + + @pytest.mark.asyncio + async def test_stop(self, run_process): + process = await run_process("sleep 10000") + await process.stop() + assert process.process.returncode == -15 + + @pytest.mark.asyncio + async def test_read_stdout(self, run_process): + process = await run_process("echo Hello df_designer") + output = await process.read_stdout() + assert output.strip().decode() == "Hello df_designer" + + @pytest.mark.asyncio + async def test_write_stdout(self, run_process): + process = await run_process("cat") + await process.write_stdin(b"DF_Designer team welcome you.\n") + output = await process.process.stdout.readline() + assert output.decode().strip() == "DF_Designer team welcome you." + + +# class TestBuildProcess: +# pass diff --git a/backend/df_designer/app/tests/services/test_process_manager.py b/backend/df_designer/app/tests/services/test_process_manager.py new file mode 100644 index 00000000..8dd5b9ae --- /dev/null +++ b/backend/df_designer/app/tests/services/test_process_manager.py @@ -0,0 +1,96 @@ +import pytest +from omegaconf import OmegaConf + +from app.core.logger_config import get_logger + +logger = get_logger(__name__) + +RUN_ID = 42 +BUILD_ID = 43 + + +class TestRunManager: + @pytest.mark.asyncio + async def test_start(self, mocker, preset, run_manager): # noqa: F811 + # Mock the RunProcess constructor whereever it's called in + # the process_manager file within the scope of this test function + run_process = mocker.patch("app.services.process_manager.RunProcess") + run_process_instance = run_process.return_value + run_process_instance.start = mocker.AsyncMock() + run_manager.get_full_info = mocker.AsyncMock(return_value=[{"id": RUN_ID}]) + + await run_manager.start(build_id=BUILD_ID, preset=preset) + + run_process.assert_called_once_with(run_manager.last_id, BUILD_ID, preset.end_status) + run_process_instance.start.assert_awaited_once_with(f"dflowd run_bot {BUILD_ID} --preset {preset.end_status}") + + assert run_manager.processes[run_manager.last_id] is run_process_instance + + @pytest.mark.asyncio + async def test_stop_success(self, mocker, run_manager): + run_manager.processes[RUN_ID] = mocker.MagicMock() + run_manager.processes[RUN_ID].stop = mocker.AsyncMock() + + await run_manager.stop(RUN_ID) + run_manager.processes[RUN_ID].stop.assert_awaited_once_with() + + @pytest.mark.asyncio + async def test_stop_with_error(self, run_manager): + with pytest.raises((RuntimeError, ProcessLookupError)): + await run_manager.stop(RUN_ID) + + # def test_check_status(self, run_manager, preset): + # pass + + @pytest.mark.asyncio + async def test_get_process_info(self, mocker, run_manager): + df_conf = OmegaConf.create( + f""" + - id: {RUN_ID} + status: stopped + """ + ) + df_conf_dict = { + "id": RUN_ID, + "status": "stopped", + } + + read_conf = mocker.patch("app.services.process_manager.read_conf") + read_conf.return_value = df_conf + + run_info = await run_manager.get_run_info(RUN_ID) + assert run_info == df_conf_dict + + @pytest.mark.asyncio + async def test_get_full_info(self, mocker, run_manager): + df_conf = OmegaConf.create( + f""" + - id: {RUN_ID} + status: stopped + - id: {RUN_ID + 1} + status: stopped + """ + ) + df_conf_dict = { + "id": RUN_ID, + "status": "stopped", + } + + read_conf = mocker.patch("app.services.process_manager.read_conf") + read_conf.return_value = df_conf + + run_info = await run_manager.get_full_info(0, 1) + assert run_info == [df_conf_dict] + + @pytest.mark.asyncio + async def test_fetch_run_logs(self, mocker, run_manager): + LOG_PATH = "df_designer/logs/runs/20240425/42_211545.log" + run_manager.get_process_info = mocker.AsyncMock(return_value={"id": RUN_ID, "log_path": LOG_PATH}) + + read_logs = mocker.patch("app.services.process_manager.read_logs", return_value=["log1", "log2"]) + + logs = await run_manager.fetch_run_logs(RUN_ID, 0, 1) + + run_manager.get_process_info.assert_awaited_once() + read_logs.assert_awaited_once_with(LOG_PATH) + assert logs == ["log1"] diff --git a/backend/df_designer/app/tests/services/test_websocket_manager.py b/backend/df_designer/app/tests/services/test_websocket_manager.py new file mode 100644 index 00000000..854b232c --- /dev/null +++ b/backend/df_designer/app/tests/services/test_websocket_manager.py @@ -0,0 +1,60 @@ +import pytest +from fastapi import WebSocket + +from app.services.process import RunProcess +from app.services.process_manager import RunManager + + +class TestWebSocketManager: + @pytest.mark.asyncio + async def test_connect(self, mocker, websocket_manager): + mocked_websocket = mocker.MagicMock(spec=WebSocket) + + await websocket_manager.connect(mocked_websocket) + + mocked_websocket.accept.assert_awaited_once_with() + assert mocked_websocket in websocket_manager.active_connections + + @pytest.mark.asyncio + async def test_disconnect(self, mocker, websocket_manager): + mocked_websocket = mocker.MagicMock(spec=WebSocket) + websocket_manager.active_connections.append(mocked_websocket) + websocket_manager.pending_tasks[mocked_websocket] = set() + + websocket_manager.disconnect(mocked_websocket) + + assert mocked_websocket not in websocket_manager.pending_tasks + assert mocked_websocket not in websocket_manager.active_connections + + @pytest.mark.asyncio + async def test_send_process_output_to_websocket(self, mocker, websocket_manager): + run_id = 42 + awaited_response = "Hello from DF-Designer" + + websocket = mocker.MagicMock(spec=WebSocket) + run_manager = mocker.MagicMock(spec=RunManager()) + run_process = mocker.MagicMock(spec=RunProcess(run_id)) + run_process.read_stdout = mocker.AsyncMock(side_effect=[awaited_response.encode(), None]) + run_manager.processes = {run_id: run_process} + + await websocket_manager.send_process_output_to_websocket(run_id, run_manager, websocket) + + assert run_process.read_stdout.call_count == 2 + websocket.send_text.assert_awaited_once_with(awaited_response) + + @pytest.mark.asyncio + async def test_forward_websocket_messages_to_process(self, mocker, websocket_manager): + run_id = 42 + awaited_message = "Hello from DF-Designer" + + websocket = mocker.MagicMock(spec=WebSocket) + websocket.receive_text = mocker.AsyncMock(side_effect=[awaited_message, None]) + run_manager = mocker.MagicMock(spec=RunManager()) + run_process = mocker.MagicMock(spec=RunProcess(run_id)) + run_process.write_stdin = mocker.AsyncMock() + run_manager.processes = {run_id: run_process} + + await websocket_manager.forward_websocket_messages_to_process(run_id, run_manager, websocket) + + assert websocket.receive_text.await_count == 2 + run_process.write_stdin.assert_called_once_with(awaited_message.encode() + b"\n") diff --git a/backend/df_designer/poetry.lock b/backend/df_designer/poetry.lock new file mode 100644 index 00000000..790cec79 --- /dev/null +++ b/backend/df_designer/poetry.lock @@ -0,0 +1,1571 @@ +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. + +[[package]] +name = "aiofiles" +version = "23.2.1" +description = "File support for asyncio." +optional = false +python-versions = ">=3.7" +files = [ + {file = "aiofiles-23.2.1-py3-none-any.whl", hash = "sha256:19297512c647d4b27a2cf7c34caa7e405c0d60b5560618a29a9fe027b18b0107"}, + {file = "aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a"}, +] + +[[package]] +name = "annotated-types" +version = "0.6.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, +] + +[[package]] +name = "antlr4-python3-runtime" +version = "4.9.3" +description = "ANTLR 4.9.3 runtime for Python 3.7" +optional = false +python-versions = "*" +files = [ + {file = "antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"}, +] + +[[package]] +name = "anyio" +version = "4.3.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +files = [ + {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, + {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] + +[[package]] +name = "arrow" +version = "1.3.0" +description = "Better dates & times for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80"}, + {file = "arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85"}, +] + +[package.dependencies] +python-dateutil = ">=2.7.0" +types-python-dateutil = ">=2.8.10" + +[package.extras] +doc = ["doc8", "sphinx (>=7.0.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx_rtd_theme (>=1.3.0)"] +test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2021.1)", "simplejson (==3.*)"] + +[[package]] +name = "binaryornot" +version = "0.4.4" +description = "Ultra-lightweight pure Python package to check if a file is binary or text." +optional = false +python-versions = "*" +files = [ + {file = "binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4"}, + {file = "binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061"}, +] + +[package.dependencies] +chardet = ">=3.0.2" + +[[package]] +name = "black" +version = "22.12.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.7" +files = [ + {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, + {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, + {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, + {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, + {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, + {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, + {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, + {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, + {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, + {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, + {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, + {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "certifi" +version = "2024.2.2" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, +] + +[[package]] +name = "chardet" +version = "5.2.0" +description = "Universal encoding detector for Python 3" +optional = false +python-versions = ">=3.7" +files = [ + {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, + {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "cookiecutter" +version = "2.6.0" +description = "A command-line utility that creates projects from project templates, e.g. creating a Python package project from a Python package project template." +optional = false +python-versions = ">=3.7" +files = [ + {file = "cookiecutter-2.6.0-py3-none-any.whl", hash = "sha256:a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d"}, + {file = "cookiecutter-2.6.0.tar.gz", hash = "sha256:db21f8169ea4f4fdc2408d48ca44859349de2647fbe494a9d6c3edfc0542c21c"}, +] + +[package.dependencies] +arrow = "*" +binaryornot = ">=0.4.4" +click = ">=7.0,<9.0.0" +Jinja2 = ">=2.7,<4.0.0" +python-slugify = ">=4.0.0" +pyyaml = ">=5.3.1" +requests = ">=2.23.0" +rich = "*" + +[[package]] +name = "dff" +version = "0.6.4.dev0" +description = "Dialog Flow Framework is a free and open-source software stack for creating chatbots, released under the terms of Apache License 2.0." +optional = false +python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8" +files = [ + {file = "dff-0.6.4.dev0-py3-none-any.whl", hash = "sha256:2bf1375bdde25492f623995bb148773d5f99b0173d547f9f7a47aa351d2a6302"}, + {file = "dff-0.6.4.dev0.tar.gz", hash = "sha256:06a44f7e43e137208bc02615e95492526afc20a9078688d5be34fdb01934bd64"}, +] + +[package.dependencies] +colorama = "*" +nest-asyncio = "*" +pydantic = ">=2.0" +typing-extensions = "*" +wrapt = "*" + +[package.extras] +benchmark = ["altair", "humanize", "pandas", "pympler", "tqdm"] +json = ["aiofiles"] +mongodb = ["motor"] +mysql = ["asyncmy", "cryptography", "sqlalchemy[asyncio]"] +pickle = ["aiofiles"] +postgresql = ["asyncpg", "sqlalchemy[asyncio]"] +redis = ["redis"] +sqlite = ["aiosqlite", "sqlalchemy[asyncio]"] +stats = ["omegaconf", "opentelemetry-exporter-otlp (>=1.20.0)", "opentelemetry-instrumentation", "requests", "tqdm"] +telegram = ["pytelegrambotapi"] +ydb = ["six", "ydb"] + +[[package]] +name = "exceptiongroup" +version = "1.2.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "fastapi" +version = "0.110.1" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fastapi-0.110.1-py3-none-any.whl", hash = "sha256:5df913203c482f820d31f48e635e022f8cbfe7350e4830ef05a3163925b1addc"}, + {file = "fastapi-0.110.1.tar.gz", hash = "sha256:6feac43ec359dfe4f45b2c18ec8c94edb8dc2dfc461d417d9e626590c071baad"}, +] + +[package.dependencies] +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +starlette = ">=0.37.2,<0.38.0" +typing-extensions = ">=4.8.0" + +[package.extras] +all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] + +[[package]] +name = "flake8" +version = "4.0.1" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.6" +files = [ + {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, + {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, +] + +[package.dependencies] +mccabe = ">=0.6.0,<0.7.0" +pycodestyle = ">=2.8.0,<2.9.0" +pyflakes = ">=2.4.0,<2.5.0" + +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "httpcore" +version = "1.0.5" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, + {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<0.26.0)"] + +[[package]] +name = "httptools" +version = "0.6.1" +description = "A collection of framework independent HTTP protocol utils." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f"}, + {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563"}, + {file = "httptools-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58"}, + {file = "httptools-0.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185"}, + {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142"}, + {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658"}, + {file = "httptools-0.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b"}, + {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1"}, + {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0"}, + {file = "httptools-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc"}, + {file = "httptools-0.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2"}, + {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837"}, + {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d"}, + {file = "httptools-0.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3"}, + {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0"}, + {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2"}, + {file = "httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90"}, + {file = "httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503"}, + {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84"}, + {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb"}, + {file = "httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949"}, + {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8e216a038d2d52ea13fdd9b9c9c7459fb80d78302b257828285eca1c773b99b3"}, + {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e802e0b2378ade99cd666b5bffb8b2a7cc8f3d28988685dc300469ea8dd86cb"}, + {file = "httptools-0.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd3e488b447046e386a30f07af05f9b38d3d368d1f7b4d8f7e10af85393db97"}, + {file = "httptools-0.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe467eb086d80217b7584e61313ebadc8d187a4d95bb62031b7bab4b205c3ba3"}, + {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3c3b214ce057c54675b00108ac42bacf2ab8f85c58e3f324a4e963bbc46424f4"}, + {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ae5b97f690badd2ca27cbf668494ee1b6d34cf1c464271ef7bfa9ca6b83ffaf"}, + {file = "httptools-0.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:405784577ba6540fa7d6ff49e37daf104e04f4b4ff2d1ac0469eaa6a20fde084"}, + {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:95fb92dd3649f9cb139e9c56604cc2d7c7bf0fc2e7c8d7fbd58f96e35eddd2a3"}, + {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dcbab042cc3ef272adc11220517278519adf8f53fd3056d0e68f0a6f891ba94e"}, + {file = "httptools-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf2372e98406efb42e93bfe10f2948e467edfd792b015f1b4ecd897903d3e8d"}, + {file = "httptools-0.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:678fcbae74477a17d103b7cae78b74800d795d702083867ce160fc202104d0da"}, + {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e0b281cf5a125c35f7f6722b65d8542d2e57331be573e9e88bc8b0115c4a7a81"}, + {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:95658c342529bba4e1d3d2b1a874db16c7cca435e8827422154c9da76ac4e13a"}, + {file = "httptools-0.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ebaec1bf683e4bf5e9fbb49b8cc36da482033596a415b3e4ebab5a4c0d7ec5e"}, + {file = "httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a"}, +] + +[package.extras] +test = ["Cython (>=0.29.24,<0.30.0)"] + +[[package]] +name = "httpx" +version = "0.27.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, + {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "httpx-ws" +version = "0.6.0" +description = "WebSockets support for HTTPX" +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx_ws-0.6.0-py3-none-any.whl", hash = "sha256:437cfca94519a4e6ae06eb5573192df6c0da85c22b1a19cc1ea0b02b05a51d25"}, + {file = "httpx_ws-0.6.0.tar.gz", hash = "sha256:60218f531fb474a2143af38568f4b7d94ba356780973443365c8e2c87882bb8c"}, +] + +[package.dependencies] +anyio = ">=4" +httpcore = ">=1.0.4" +httpx = ">=0.23.1" +wsproto = "*" + +[[package]] +name = "idna" +version = "3.7" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "isort" +version = "5.13.2" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] + +[package.extras] +colors = ["colorama (>=0.4.6)"] + +[[package]] +name = "jinja2" +version = "3.1.3" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[package]] +name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = "*" +files = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +description = "Patch asyncio to allow nested event loops" +optional = false +python-versions = ">=3.5" +files = [ + {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, + {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, +] + +[[package]] +name = "omegaconf" +version = "2.3.0" +description = "A flexible configuration library" +optional = false +python-versions = ">=3.6" +files = [ + {file = "omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b"}, + {file = "omegaconf-2.3.0.tar.gz", hash = "sha256:d5d4b6d29955cc50ad50c46dc269bcd92c6e00f5f90d23ab5fee7bfca4ba4cc7"}, +] + +[package.dependencies] +antlr4-python3-runtime = "==4.9.*" +PyYAML = ">=5.1.0" + +[[package]] +name = "packaging" +version = "24.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.2.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] + +[[package]] +name = "pluggy" +version = "1.4.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pycodestyle" +version = "2.8.0" +description = "Python style guide checker" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, + {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, +] + +[[package]] +name = "pydantic" +version = "2.7.0" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.7.0-py3-none-any.whl", hash = "sha256:9dee74a271705f14f9a1567671d144a851c675b072736f0a7b2608fd9e495352"}, + {file = "pydantic-2.7.0.tar.gz", hash = "sha256:b5ecdd42262ca2462e2624793551e80911a1e989f462910bb81aef974b4bb383"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +pydantic-core = "2.18.1" +typing-extensions = ">=4.6.1" + +[package.extras] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.18.1" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ee9cf33e7fe14243f5ca6977658eb7d1042caaa66847daacbd2117adb258b226"}, + {file = "pydantic_core-2.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b7bbb97d82659ac8b37450c60ff2e9f97e4eb0f8a8a3645a5568b9334b08b50"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df4249b579e75094f7e9bb4bd28231acf55e308bf686b952f43100a5a0be394c"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d0491006a6ad20507aec2be72e7831a42efc93193d2402018007ff827dc62926"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ae80f72bb7a3e397ab37b53a2b49c62cc5496412e71bc4f1277620a7ce3f52b"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58aca931bef83217fca7a390e0486ae327c4af9c3e941adb75f8772f8eeb03a1"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be91ad664fc9245404a789d60cba1e91c26b1454ba136d2a1bf0c2ac0c0505a"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:667880321e916a8920ef49f5d50e7983792cf59f3b6079f3c9dac2b88a311d17"}, + {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f7054fdc556f5421f01e39cbb767d5ec5c1139ea98c3e5b350e02e62201740c7"}, + {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:030e4f9516f9947f38179249778709a460a3adb516bf39b5eb9066fcfe43d0e6"}, + {file = "pydantic_core-2.18.1-cp310-none-win32.whl", hash = "sha256:2e91711e36e229978d92642bfc3546333a9127ecebb3f2761372e096395fc649"}, + {file = "pydantic_core-2.18.1-cp310-none-win_amd64.whl", hash = "sha256:9a29726f91c6cb390b3c2338f0df5cd3e216ad7a938762d11c994bb37552edb0"}, + {file = "pydantic_core-2.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9ece8a49696669d483d206b4474c367852c44815fca23ac4e48b72b339807f80"}, + {file = "pydantic_core-2.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a5d83efc109ceddb99abd2c1316298ced2adb4570410defe766851a804fcd5b"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7973c381283783cd1043a8c8f61ea5ce7a3a58b0369f0ee0ee975eaf2f2a1b"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54c7375c62190a7845091f521add19b0f026bcf6ae674bdb89f296972272e86d"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd63cec4e26e790b70544ae5cc48d11b515b09e05fdd5eff12e3195f54b8a586"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:561cf62c8a3498406495cfc49eee086ed2bb186d08bcc65812b75fda42c38294"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68717c38a68e37af87c4da20e08f3e27d7e4212e99e96c3d875fbf3f4812abfc"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d5728e93d28a3c63ee513d9ffbac9c5989de8c76e049dbcb5bfe4b923a9739d"}, + {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f0f17814c505f07806e22b28856c59ac80cee7dd0fbb152aed273e116378f519"}, + {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d816f44a51ba5175394bc6c7879ca0bd2be560b2c9e9f3411ef3a4cbe644c2e9"}, + {file = "pydantic_core-2.18.1-cp311-none-win32.whl", hash = "sha256:09f03dfc0ef8c22622eaa8608caa4a1e189cfb83ce847045eca34f690895eccb"}, + {file = "pydantic_core-2.18.1-cp311-none-win_amd64.whl", hash = "sha256:27f1009dc292f3b7ca77feb3571c537276b9aad5dd4efb471ac88a8bd09024e9"}, + {file = "pydantic_core-2.18.1-cp311-none-win_arm64.whl", hash = "sha256:48dd883db92e92519201f2b01cafa881e5f7125666141a49ffba8b9facc072b0"}, + {file = "pydantic_core-2.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b6b0e4912030c6f28bcb72b9ebe4989d6dc2eebcd2a9cdc35fefc38052dd4fe8"}, + {file = "pydantic_core-2.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3202a429fe825b699c57892d4371c74cc3456d8d71b7f35d6028c96dfecad31"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3982b0a32d0a88b3907e4b0dc36809fda477f0757c59a505d4e9b455f384b8b"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25595ac311f20e5324d1941909b0d12933f1fd2171075fcff763e90f43e92a0d"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14fe73881cf8e4cbdaded8ca0aa671635b597e42447fec7060d0868b52d074e6"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca976884ce34070799e4dfc6fbd68cb1d181db1eefe4a3a94798ddfb34b8867f"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684d840d2c9ec5de9cb397fcb3f36d5ebb6fa0d94734f9886032dd796c1ead06"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:54764c083bbe0264f0f746cefcded6cb08fbbaaf1ad1d78fb8a4c30cff999a90"}, + {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:201713f2f462e5c015b343e86e68bd8a530a4f76609b33d8f0ec65d2b921712a"}, + {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fd1a9edb9dd9d79fbeac1ea1f9a8dd527a6113b18d2e9bcc0d541d308dae639b"}, + {file = "pydantic_core-2.18.1-cp312-none-win32.whl", hash = "sha256:d5e6b7155b8197b329dc787356cfd2684c9d6a6b1a197f6bbf45f5555a98d411"}, + {file = "pydantic_core-2.18.1-cp312-none-win_amd64.whl", hash = "sha256:9376d83d686ec62e8b19c0ac3bf8d28d8a5981d0df290196fb6ef24d8a26f0d6"}, + {file = "pydantic_core-2.18.1-cp312-none-win_arm64.whl", hash = "sha256:c562b49c96906b4029b5685075fe1ebd3b5cc2601dfa0b9e16c2c09d6cbce048"}, + {file = "pydantic_core-2.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:3e352f0191d99fe617371096845070dee295444979efb8f27ad941227de6ad09"}, + {file = "pydantic_core-2.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0295d52b012cbe0d3059b1dba99159c3be55e632aae1999ab74ae2bd86a33d7"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56823a92075780582d1ffd4489a2e61d56fd3ebb4b40b713d63f96dd92d28144"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd3f79e17b56741b5177bcc36307750d50ea0698df6aa82f69c7db32d968c1c2"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38a5024de321d672a132b1834a66eeb7931959c59964b777e8f32dbe9523f6b1"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ce426ee691319d4767748c8e0895cfc56593d725594e415f274059bcf3cb76"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2adaeea59849ec0939af5c5d476935f2bab4b7f0335b0110f0f069a41024278e"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9b6431559676a1079eac0f52d6d0721fb8e3c5ba43c37bc537c8c83724031feb"}, + {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:85233abb44bc18d16e72dc05bf13848a36f363f83757541f1a97db2f8d58cfd9"}, + {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:641a018af4fe48be57a2b3d7a1f0f5dbca07c1d00951d3d7463f0ac9dac66622"}, + {file = "pydantic_core-2.18.1-cp38-none-win32.whl", hash = "sha256:63d7523cd95d2fde0d28dc42968ac731b5bb1e516cc56b93a50ab293f4daeaad"}, + {file = "pydantic_core-2.18.1-cp38-none-win_amd64.whl", hash = "sha256:907a4d7720abfcb1c81619863efd47c8a85d26a257a2dbebdb87c3b847df0278"}, + {file = "pydantic_core-2.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:aad17e462f42ddbef5984d70c40bfc4146c322a2da79715932cd8976317054de"}, + {file = "pydantic_core-2.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:94b9769ba435b598b547c762184bcfc4783d0d4c7771b04a3b45775c3589ca44"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80e0e57cc704a52fb1b48f16d5b2c8818da087dbee6f98d9bf19546930dc64b5"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76b86e24039c35280ceee6dce7e62945eb93a5175d43689ba98360ab31eebc4a"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a05db5013ec0ca4a32cc6433f53faa2a014ec364031408540ba858c2172bb0"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:250ae39445cb5475e483a36b1061af1bc233de3e9ad0f4f76a71b66231b07f88"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a32204489259786a923e02990249c65b0f17235073149d0033efcebe80095570"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6395a4435fa26519fd96fdccb77e9d00ddae9dd6c742309bd0b5610609ad7fb2"}, + {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2533ad2883f001efa72f3d0e733fb846710c3af6dcdd544fe5bf14fa5fe2d7db"}, + {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b560b72ed4816aee52783c66854d96157fd8175631f01ef58e894cc57c84f0f6"}, + {file = "pydantic_core-2.18.1-cp39-none-win32.whl", hash = "sha256:582cf2cead97c9e382a7f4d3b744cf0ef1a6e815e44d3aa81af3ad98762f5a9b"}, + {file = "pydantic_core-2.18.1-cp39-none-win_amd64.whl", hash = "sha256:ca71d501629d1fa50ea7fa3b08ba884fe10cefc559f5c6c8dfe9036c16e8ae89"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e178e5b66a06ec5bf51668ec0d4ac8cfb2bdcb553b2c207d58148340efd00143"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:72722ce529a76a4637a60be18bd789d8fb871e84472490ed7ddff62d5fed620d"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fe0c1ce5b129455e43f941f7a46f61f3d3861e571f2905d55cdbb8b5c6f5e2c"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4284c621f06a72ce2cb55f74ea3150113d926a6eb78ab38340c08f770eb9b4d"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a0c3e718f4e064efde68092d9d974e39572c14e56726ecfaeebbe6544521f47"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2027493cc44c23b598cfaf200936110433d9caa84e2c6cf487a83999638a96ac"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:76909849d1a6bffa5a07742294f3fa1d357dc917cb1fe7b470afbc3a7579d539"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ee7ccc7fb7e921d767f853b47814c3048c7de536663e82fbc37f5eb0d532224b"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee2794111c188548a4547eccc73a6a8527fe2af6cf25e1a4ebda2fd01cdd2e60"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a139fe9f298dc097349fb4f28c8b81cc7a202dbfba66af0e14be5cfca4ef7ce5"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d074b07a10c391fc5bbdcb37b2f16f20fcd9e51e10d01652ab298c0d07908ee2"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c69567ddbac186e8c0aadc1f324a60a564cfe25e43ef2ce81bcc4b8c3abffbae"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf1c7b78cddb5af00971ad5294a4583188bda1495b13760d9f03c9483bb6203"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2684a94fdfd1b146ff10689c6e4e815f6a01141781c493b97342cdc5b06f4d5d"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:73c1bc8a86a5c9e8721a088df234265317692d0b5cd9e86e975ce3bc3db62a59"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e60defc3c15defb70bb38dd605ff7e0fae5f6c9c7cbfe0ad7868582cb7e844a6"}, + {file = "pydantic_core-2.18.1.tar.gz", hash = "sha256:de9d3e8717560eb05e28739d1b35e4eac2e458553a52a301e51352a7ffc86a35"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pydantic-settings" +version = "2.2.1" +description = "Settings management using Pydantic" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"}, + {file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"}, +] + +[package.dependencies] +pydantic = ">=2.3.0" +python-dotenv = ">=0.21.0" + +[package.extras] +toml = ["tomli (>=2.0.1)"] +yaml = ["pyyaml (>=6.0.1)"] + +[[package]] +name = "pyflakes" +version = "2.4.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, + {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, +] + +[[package]] +name = "pygments" +version = "2.17.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, +] + +[package.extras] +plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pytest" +version = "8.1.1" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7"}, + {file = "pytest-8.1.1.tar.gz", hash = "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.4,<2.0" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.23.6" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-asyncio-0.23.6.tar.gz", hash = "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f"}, + {file = "pytest_asyncio-0.23.6-py3-none-any.whl", hash = "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a"}, +] + +[package.dependencies] +pytest = ">=7.0.0,<9" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] + +[[package]] +name = "pytest-mock" +version = "3.14.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, + {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, +] + +[package.dependencies] +pytest = ">=6.2.5" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-dotenv" +version = "1.0.1" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, + {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + +[[package]] +name = "python-slugify" +version = "8.0.4" +description = "A Python slugify application that also handles Unicode" +optional = false +python-versions = ">=3.7" +files = [ + {file = "python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856"}, + {file = "python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"}, +] + +[package.dependencies] +text-unidecode = ">=1.3" + +[package.extras] +unidecode = ["Unidecode (>=1.1.1)"] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rich" +version = "13.7.1" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, + {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "starlette" +version = "0.37.2" +description = "The little ASGI library that shines." +optional = false +python-versions = ">=3.8" +files = [ + {file = "starlette-0.37.2-py3-none-any.whl", hash = "sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee"}, + {file = "starlette-0.37.2.tar.gz", hash = "sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823"}, +] + +[package.dependencies] +anyio = ">=3.4.0,<5" + +[package.extras] +full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] + +[[package]] +name = "text-unidecode" +version = "1.3" +description = "The most basic Text::Unidecode port" +optional = false +python-versions = "*" +files = [ + {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, + {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "typer" +version = "0.9.4" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.6" +files = [ + {file = "typer-0.9.4-py3-none-any.whl", hash = "sha256:aa6c4a4e2329d868b80ecbaf16f807f2b54e192209d7ac9dd42691d63f7a54eb"}, + {file = "typer-0.9.4.tar.gz", hash = "sha256:f714c2d90afae3a7929fcd72a3abb08df305e1ff61719381384211c4070af57f"}, +] + +[package.dependencies] +click = ">=7.1.1,<9.0.0" +typing-extensions = ">=3.7.4.3" + +[package.extras] +all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] +dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] +doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] +test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.971)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] + +[[package]] +name = "types-python-dateutil" +version = "2.9.0.20240316" +description = "Typing stubs for python-dateutil" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-python-dateutil-2.9.0.20240316.tar.gz", hash = "sha256:5d2f2e240b86905e40944dd787db6da9263f0deabef1076ddaed797351ec0202"}, + {file = "types_python_dateutil-2.9.0.20240316-py3-none-any.whl", hash = "sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b"}, +] + +[[package]] +name = "typing-extensions" +version = "4.11.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, + {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, +] + +[[package]] +name = "urllib3" +version = "2.2.1" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "uvicorn" +version = "0.28.1" +description = "The lightning-fast ASGI server." +optional = false +python-versions = ">=3.8" +files = [ + {file = "uvicorn-0.28.1-py3-none-any.whl", hash = "sha256:5162f6d652f545be91b1feeaee8180774af143965ca9dc8a47ff1dc6bafa4ad5"}, + {file = "uvicorn-0.28.1.tar.gz", hash = "sha256:08103e79d546b6cf20f67c7e5e434d2cf500a6e29b28773e407250c54fc4fa3c"}, +] + +[package.dependencies] +click = ">=7.0" +colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} +h11 = ">=0.8" +httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} +python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} +typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} +uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} + +[package.extras] +standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "uvloop" +version = "0.19.0" +description = "Fast implementation of asyncio event loop on top of libuv" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e"}, + {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428"}, + {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8"}, + {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849"}, + {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957"}, + {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd"}, + {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef"}, + {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2"}, + {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1"}, + {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24"}, + {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533"}, + {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12"}, + {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650"}, + {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec"}, + {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc"}, + {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6"}, + {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593"}, + {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3"}, + {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:78ab247f0b5671cc887c31d33f9b3abfb88d2614b84e4303f1a63b46c046c8bd"}, + {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:472d61143059c84947aa8bb74eabbace30d577a03a1805b77933d6bd13ddebbd"}, + {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45bf4c24c19fb8a50902ae37c5de50da81de4922af65baf760f7c0c42e1088be"}, + {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271718e26b3e17906b28b67314c45d19106112067205119dddbd834c2b7ce797"}, + {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:34175c9fd2a4bc3adc1380e1261f60306344e3407c20a4d684fd5f3be010fa3d"}, + {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e27f100e1ff17f6feeb1f33968bc185bf8ce41ca557deee9d9bbbffeb72030b7"}, + {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13dfdf492af0aa0a0edf66807d2b465607d11c4fa48f4a1fd41cbea5b18e8e8b"}, + {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e3d4e85ac060e2342ff85e90d0c04157acb210b9ce508e784a944f852a40e67"}, + {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca4956c9ab567d87d59d49fa3704cf29e37109ad348f2d5223c9bf761a332e7"}, + {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f467a5fd23b4fc43ed86342641f3936a68ded707f4627622fa3f82a120e18256"}, + {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:492e2c32c2af3f971473bc22f086513cedfc66a130756145a931a90c3958cb17"}, + {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2df95fca285a9f5bfe730e51945ffe2fa71ccbfdde3b0da5772b4ee4f2e770d5"}, + {file = "uvloop-0.19.0.tar.gz", hash = "sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd"}, +] + +[package.extras] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] + +[[package]] +name = "watchfiles" +version = "0.21.0" +description = "Simple, modern and high performance file watching and code reload in python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "watchfiles-0.21.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:27b4035013f1ea49c6c0b42d983133b136637a527e48c132d368eb19bf1ac6aa"}, + {file = "watchfiles-0.21.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c81818595eff6e92535ff32825f31c116f867f64ff8cdf6562cd1d6b2e1e8f3e"}, + {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6c107ea3cf2bd07199d66f156e3ea756d1b84dfd43b542b2d870b77868c98c03"}, + {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d9ac347653ebd95839a7c607608703b20bc07e577e870d824fa4801bc1cb124"}, + {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5eb86c6acb498208e7663ca22dbe68ca2cf42ab5bf1c776670a50919a56e64ab"}, + {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f564bf68404144ea6b87a78a3f910cc8de216c6b12a4cf0b27718bf4ec38d303"}, + {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d0f32ebfaa9c6011f8454994f86108c2eb9c79b8b7de00b36d558cadcedaa3d"}, + {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6d45d9b699ecbac6c7bd8e0a2609767491540403610962968d258fd6405c17c"}, + {file = "watchfiles-0.21.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:aff06b2cac3ef4616e26ba17a9c250c1fe9dd8a5d907d0193f84c499b1b6e6a9"}, + {file = "watchfiles-0.21.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d9792dff410f266051025ecfaa927078b94cc7478954b06796a9756ccc7e14a9"}, + {file = "watchfiles-0.21.0-cp310-none-win32.whl", hash = "sha256:214cee7f9e09150d4fb42e24919a1e74d8c9b8a9306ed1474ecaddcd5479c293"}, + {file = "watchfiles-0.21.0-cp310-none-win_amd64.whl", hash = "sha256:1ad7247d79f9f55bb25ab1778fd47f32d70cf36053941f07de0b7c4e96b5d235"}, + {file = "watchfiles-0.21.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:668c265d90de8ae914f860d3eeb164534ba2e836811f91fecc7050416ee70aa7"}, + {file = "watchfiles-0.21.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a23092a992e61c3a6a70f350a56db7197242f3490da9c87b500f389b2d01eef"}, + {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e7941bbcfdded9c26b0bf720cb7e6fd803d95a55d2c14b4bd1f6a2772230c586"}, + {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11cd0c3100e2233e9c53106265da31d574355c288e15259c0d40a4405cbae317"}, + {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78f30cbe8b2ce770160d3c08cff01b2ae9306fe66ce899b73f0409dc1846c1b"}, + {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6674b00b9756b0af620aa2a3346b01f8e2a3dc729d25617e1b89cf6af4a54eb1"}, + {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd7ac678b92b29ba630d8c842d8ad6c555abda1b9ef044d6cc092dacbfc9719d"}, + {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c873345680c1b87f1e09e0eaf8cf6c891b9851d8b4d3645e7efe2ec20a20cc7"}, + {file = "watchfiles-0.21.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49f56e6ecc2503e7dbe233fa328b2be1a7797d31548e7a193237dcdf1ad0eee0"}, + {file = "watchfiles-0.21.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:02d91cbac553a3ad141db016e3350b03184deaafeba09b9d6439826ee594b365"}, + {file = "watchfiles-0.21.0-cp311-none-win32.whl", hash = "sha256:ebe684d7d26239e23d102a2bad2a358dedf18e462e8808778703427d1f584400"}, + {file = "watchfiles-0.21.0-cp311-none-win_amd64.whl", hash = "sha256:4566006aa44cb0d21b8ab53baf4b9c667a0ed23efe4aaad8c227bfba0bf15cbe"}, + {file = "watchfiles-0.21.0-cp311-none-win_arm64.whl", hash = "sha256:c550a56bf209a3d987d5a975cdf2063b3389a5d16caf29db4bdddeae49f22078"}, + {file = "watchfiles-0.21.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:51ddac60b96a42c15d24fbdc7a4bfcd02b5a29c047b7f8bf63d3f6f5a860949a"}, + {file = "watchfiles-0.21.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:511f0b034120cd1989932bf1e9081aa9fb00f1f949fbd2d9cab6264916ae89b1"}, + {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cfb92d49dbb95ec7a07511bc9efb0faff8fe24ef3805662b8d6808ba8409a71a"}, + {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f92944efc564867bbf841c823c8b71bb0be75e06b8ce45c084b46411475a915"}, + {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:642d66b75eda909fd1112d35c53816d59789a4b38c141a96d62f50a3ef9b3360"}, + {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d23bcd6c8eaa6324fe109d8cac01b41fe9a54b8c498af9ce464c1aeeb99903d6"}, + {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18d5b4da8cf3e41895b34e8c37d13c9ed294954907929aacd95153508d5d89d7"}, + {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b8d1eae0f65441963d805f766c7e9cd092f91e0c600c820c764a4ff71a0764c"}, + {file = "watchfiles-0.21.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1fd9a5205139f3c6bb60d11f6072e0552f0a20b712c85f43d42342d162be1235"}, + {file = "watchfiles-0.21.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a1e3014a625bcf107fbf38eece0e47fa0190e52e45dc6eee5a8265ddc6dc5ea7"}, + {file = "watchfiles-0.21.0-cp312-none-win32.whl", hash = "sha256:9d09869f2c5a6f2d9df50ce3064b3391d3ecb6dced708ad64467b9e4f2c9bef3"}, + {file = "watchfiles-0.21.0-cp312-none-win_amd64.whl", hash = "sha256:18722b50783b5e30a18a8a5db3006bab146d2b705c92eb9a94f78c72beb94094"}, + {file = "watchfiles-0.21.0-cp312-none-win_arm64.whl", hash = "sha256:a3b9bec9579a15fb3ca2d9878deae789df72f2b0fdaf90ad49ee389cad5edab6"}, + {file = "watchfiles-0.21.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:4ea10a29aa5de67de02256a28d1bf53d21322295cb00bd2d57fcd19b850ebd99"}, + {file = "watchfiles-0.21.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:40bca549fdc929b470dd1dbfcb47b3295cb46a6d2c90e50588b0a1b3bd98f429"}, + {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9b37a7ba223b2f26122c148bb8d09a9ff312afca998c48c725ff5a0a632145f7"}, + {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec8c8900dc5c83650a63dd48c4d1d245343f904c4b64b48798c67a3767d7e165"}, + {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ad3fe0a3567c2f0f629d800409cd528cb6251da12e81a1f765e5c5345fd0137"}, + {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d353c4cfda586db2a176ce42c88f2fc31ec25e50212650c89fdd0f560ee507b"}, + {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:83a696da8922314ff2aec02987eefb03784f473281d740bf9170181829133765"}, + {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a03651352fc20975ee2a707cd2d74a386cd303cc688f407296064ad1e6d1562"}, + {file = "watchfiles-0.21.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3ad692bc7792be8c32918c699638b660c0de078a6cbe464c46e1340dadb94c19"}, + {file = "watchfiles-0.21.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06247538e8253975bdb328e7683f8515ff5ff041f43be6c40bff62d989b7d0b0"}, + {file = "watchfiles-0.21.0-cp38-none-win32.whl", hash = "sha256:9a0aa47f94ea9a0b39dd30850b0adf2e1cd32a8b4f9c7aa443d852aacf9ca214"}, + {file = "watchfiles-0.21.0-cp38-none-win_amd64.whl", hash = "sha256:8d5f400326840934e3507701f9f7269247f7c026d1b6cfd49477d2be0933cfca"}, + {file = "watchfiles-0.21.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:7f762a1a85a12cc3484f77eee7be87b10f8c50b0b787bb02f4e357403cad0c0e"}, + {file = "watchfiles-0.21.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6e9be3ef84e2bb9710f3f777accce25556f4a71e15d2b73223788d528fcc2052"}, + {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4c48a10d17571d1275701e14a601e36959ffada3add8cdbc9e5061a6e3579a5d"}, + {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c889025f59884423428c261f212e04d438de865beda0b1e1babab85ef4c0f01"}, + {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:66fac0c238ab9a2e72d026b5fb91cb902c146202bbd29a9a1a44e8db7b710b6f"}, + {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4a21f71885aa2744719459951819e7bf5a906a6448a6b2bbce8e9cc9f2c8128"}, + {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c9198c989f47898b2c22201756f73249de3748e0fc9de44adaf54a8b259cc0c"}, + {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8f57c4461cd24fda22493109c45b3980863c58a25b8bec885ca8bea6b8d4b28"}, + {file = "watchfiles-0.21.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:853853cbf7bf9408b404754b92512ebe3e3a83587503d766d23e6bf83d092ee6"}, + {file = "watchfiles-0.21.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d5b1dc0e708fad9f92c296ab2f948af403bf201db8fb2eb4c8179db143732e49"}, + {file = "watchfiles-0.21.0-cp39-none-win32.whl", hash = "sha256:59137c0c6826bd56c710d1d2bda81553b5e6b7c84d5a676747d80caf0409ad94"}, + {file = "watchfiles-0.21.0-cp39-none-win_amd64.whl", hash = "sha256:6cb8fdc044909e2078c248986f2fc76f911f72b51ea4a4fbbf472e01d14faa58"}, + {file = "watchfiles-0.21.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab03a90b305d2588e8352168e8c5a1520b721d2d367f31e9332c4235b30b8994"}, + {file = "watchfiles-0.21.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:927c589500f9f41e370b0125c12ac9e7d3a2fd166b89e9ee2828b3dda20bfe6f"}, + {file = "watchfiles-0.21.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bd467213195e76f838caf2c28cd65e58302d0254e636e7c0fca81efa4a2e62c"}, + {file = "watchfiles-0.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02b73130687bc3f6bb79d8a170959042eb56eb3a42df3671c79b428cd73f17cc"}, + {file = "watchfiles-0.21.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:08dca260e85ffae975448e344834d765983237ad6dc308231aa16e7933db763e"}, + {file = "watchfiles-0.21.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:3ccceb50c611c433145502735e0370877cced72a6c70fd2410238bcbc7fe51d8"}, + {file = "watchfiles-0.21.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57d430f5fb63fea141ab71ca9c064e80de3a20b427ca2febcbfcef70ff0ce895"}, + {file = "watchfiles-0.21.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dd5fad9b9c0dd89904bbdea978ce89a2b692a7ee8a0ce19b940e538c88a809c"}, + {file = "watchfiles-0.21.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:be6dd5d52b73018b21adc1c5d28ac0c68184a64769052dfeb0c5d9998e7f56a2"}, + {file = "watchfiles-0.21.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b3cab0e06143768499384a8a5efb9c4dc53e19382952859e4802f294214f36ec"}, + {file = "watchfiles-0.21.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c6ed10c2497e5fedadf61e465b3ca12a19f96004c15dcffe4bd442ebadc2d85"}, + {file = "watchfiles-0.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43babacef21c519bc6631c5fce2a61eccdfc011b4bcb9047255e9620732c8097"}, + {file = "watchfiles-0.21.0.tar.gz", hash = "sha256:c76c635fabf542bb78524905718c39f736a98e5ab25b23ec6d4abede1a85a6a3"}, +] + +[package.dependencies] +anyio = ">=3.0.0" + +[[package]] +name = "websockets" +version = "12.0" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"}, + {file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"}, + {file = "websockets-12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547"}, + {file = "websockets-12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2"}, + {file = "websockets-12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558"}, + {file = "websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480"}, + {file = "websockets-12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c"}, + {file = "websockets-12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8"}, + {file = "websockets-12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603"}, + {file = "websockets-12.0-cp310-cp310-win32.whl", hash = "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f"}, + {file = "websockets-12.0-cp310-cp310-win_amd64.whl", hash = "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf"}, + {file = "websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4"}, + {file = "websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f"}, + {file = "websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3"}, + {file = "websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c"}, + {file = "websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45"}, + {file = "websockets-12.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04"}, + {file = "websockets-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447"}, + {file = "websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca"}, + {file = "websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53"}, + {file = "websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402"}, + {file = "websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b"}, + {file = "websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df"}, + {file = "websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc"}, + {file = "websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b"}, + {file = "websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb"}, + {file = "websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92"}, + {file = "websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed"}, + {file = "websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5"}, + {file = "websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2"}, + {file = "websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113"}, + {file = "websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d"}, + {file = "websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f"}, + {file = "websockets-12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5f6ffe2c6598f7f7207eef9a1228b6f5c818f9f4d53ee920aacd35cec8110438"}, + {file = "websockets-12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9edf3fc590cc2ec20dc9d7a45108b5bbaf21c0d89f9fd3fd1685e223771dc0b2"}, + {file = "websockets-12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8572132c7be52632201a35f5e08348137f658e5ffd21f51f94572ca6c05ea81d"}, + {file = "websockets-12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604428d1b87edbf02b233e2c207d7d528460fa978f9e391bd8aaf9c8311de137"}, + {file = "websockets-12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a9d160fd080c6285e202327aba140fc9a0d910b09e423afff4ae5cbbf1c7205"}, + {file = "websockets-12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b4aafed34653e465eb77b7c93ef058516cb5acf3eb21e42f33928616172def"}, + {file = "websockets-12.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b2ee7288b85959797970114deae81ab41b731f19ebcd3bd499ae9ca0e3f1d2c8"}, + {file = "websockets-12.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7fa3d25e81bfe6a89718e9791128398a50dec6d57faf23770787ff441d851967"}, + {file = "websockets-12.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a571f035a47212288e3b3519944f6bf4ac7bc7553243e41eac50dd48552b6df7"}, + {file = "websockets-12.0-cp38-cp38-win32.whl", hash = "sha256:3c6cc1360c10c17463aadd29dd3af332d4a1adaa8796f6b0e9f9df1fdb0bad62"}, + {file = "websockets-12.0-cp38-cp38-win_amd64.whl", hash = "sha256:1bf386089178ea69d720f8db6199a0504a406209a0fc23e603b27b300fdd6892"}, + {file = "websockets-12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ab3d732ad50a4fbd04a4490ef08acd0517b6ae6b77eb967251f4c263011a990d"}, + {file = "websockets-12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1d9697f3337a89691e3bd8dc56dea45a6f6d975f92e7d5f773bc715c15dde28"}, + {file = "websockets-12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1df2fbd2c8a98d38a66f5238484405b8d1d16f929bb7a33ed73e4801222a6f53"}, + {file = "websockets-12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23509452b3bc38e3a057382c2e941d5ac2e01e251acce7adc74011d7d8de434c"}, + {file = "websockets-12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e5fc14ec6ea568200ea4ef46545073da81900a2b67b3e666f04adf53ad452ec"}, + {file = "websockets-12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46e71dbbd12850224243f5d2aeec90f0aaa0f2dde5aeeb8fc8df21e04d99eff9"}, + {file = "websockets-12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b81f90dcc6c85a9b7f29873beb56c94c85d6f0dac2ea8b60d995bd18bf3e2aae"}, + {file = "websockets-12.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a02413bc474feda2849c59ed2dfb2cddb4cd3d2f03a2fedec51d6e959d9b608b"}, + {file = "websockets-12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bbe6013f9f791944ed31ca08b077e26249309639313fff132bfbf3ba105673b9"}, + {file = "websockets-12.0-cp39-cp39-win32.whl", hash = "sha256:cbe83a6bbdf207ff0541de01e11904827540aa069293696dd528a6640bd6a5f6"}, + {file = "websockets-12.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc4e7fa5414512b481a2483775a8e8be7803a35b30ca805afa4998a84f9fd9e8"}, + {file = "websockets-12.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd"}, + {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870"}, + {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077"}, + {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b"}, + {file = "websockets-12.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30"}, + {file = "websockets-12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6"}, + {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123"}, + {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931"}, + {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2"}, + {file = "websockets-12.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468"}, + {file = "websockets-12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b"}, + {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399"}, + {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7"}, + {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611"}, + {file = "websockets-12.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370"}, + {file = "websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e"}, + {file = "websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b"}, +] + +[[package]] +name = "wrapt" +version = "1.16.0" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = ">=3.6" +files = [ + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, + {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, + {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, + {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, + {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, + {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, + {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, + {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, +] + +[[package]] +name = "wsproto" +version = "1.2.0" +description = "WebSockets state-machine based protocol implementation" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"}, + {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"}, +] + +[package.dependencies] +h11 = ">=0.9.0,<1" + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "cd2676c8cf6f5295bbdc51457c722ee03a05b85117b73e99b21de8bc465b040c" diff --git a/backend/df_designer/pyproject.toml b/backend/df_designer/pyproject.toml new file mode 100644 index 00000000..b0c83662 --- /dev/null +++ b/backend/df_designer/pyproject.toml @@ -0,0 +1,40 @@ +[tool.poetry] +name = "dflowd" +version = "0.1.0-beta.0" +description = "Dialog Flow Designer" +license = "Apache-2.0" +authors = [ + "Denis Kuznetsov ", + "Maks Rogatkin ", + "Rami Mashkouk ", +] +readme = "README.md" +packages = [{include = "app"}] + +[tool.poetry.dependencies] +python = "^3.10" +fastapi = "^0.110.0" +uvicorn = {extras = ["standard"], version = "^0.28.0"} +pydantic = "^2.6.3" +typer = "^0.9.0" +pydantic-settings = "^2.2.1" +aiofiles = "^23.2.1" +cookiecutter = "^2.6.0" +dff = "==0.6.4.dev0" +omegaconf = "^2.3.0" +pytest = "^8.1.1" +pytest-asyncio = "^0.23.6" +pytest-mock = "^3.14.0" +httpx = "^0.27.0" +httpx-ws = "^0.6.0" + +[tool.poetry.scripts] +dflowd = "app.cli:cli" + +[tool.poetry.group.lint] +optional = true + +[tool.poetry.group.lint.dependencies] +isort = "^5" +black = "^22" +flake8 = "^4" diff --git a/backend/df_designer/run.sh b/backend/df_designer/run.sh new file mode 100644 index 00000000..a85b4608 --- /dev/null +++ b/backend/df_designer/run.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +export APP_MODULE=${APP_MODULE-app.main:app} +export HOST=${HOST:-0.0.0.0} +export PORT=${PORT:-8001} + +exec uvicorn --reload --host $HOST --port $PORT "$APP_MODULE" \ No newline at end of file diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 00000000..9a4b6c76 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,15 @@ +volumes: + project_data: + +services: + backend: + build: + args: + PROJECT_DIR: df_designer_project + context: ./ + dockerfile: Dockerfile + ports: + - 8000:8000 + volumes: + - project_data:/src2/df_designer_project +version: '3.8' diff --git a/cypress.config.ts b/cypress.config.ts new file mode 100644 index 00000000..8959a4f2 --- /dev/null +++ b/cypress.config.ts @@ -0,0 +1,7 @@ +export default { + e2e: { + setupNodeEvents(on, config) { + // implement node event listeners here + }, + }, +}; diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs new file mode 100644 index 00000000..b8f7a50d --- /dev/null +++ b/frontend/.eslintrc.cjs @@ -0,0 +1,19 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + "@typescript-eslint/no-unused-vars": "warn", + }, +} diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 00000000..0d6babed --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,30 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: + +- Configure the top-level `parserOptions` property like this: + +```js +export default { + // other rules... + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['./tsconfig.json', './tsconfig.node.json'], + tsconfigRootDir: __dirname, + }, +} +``` + +- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` +- Optionally add `plugin:@typescript-eslint/stylistic-type-checked` +- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list diff --git a/frontend/bun.lockb b/frontend/bun.lockb new file mode 100755 index 00000000..d6dce856 Binary files /dev/null and b/frontend/bun.lockb differ diff --git a/frontend/cypress.config.ts b/frontend/cypress.config.ts new file mode 100644 index 00000000..17161e32 --- /dev/null +++ b/frontend/cypress.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from "cypress"; + +export default defineConfig({ + e2e: { + setupNodeEvents(on, config) { + // implement node event listeners here + }, + }, +}); diff --git a/frontend/cypress/e2e/spec.cy.ts b/frontend/cypress/e2e/spec.cy.ts new file mode 100644 index 00000000..762f70b5 --- /dev/null +++ b/frontend/cypress/e2e/spec.cy.ts @@ -0,0 +1,78 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +describe("check run and edit flow", () => { + it("add run edit flow", () => { + cy.visit("http://localhost:5173/app/home") + cy.location("pathname").should("eq", "/app/home") + cy.get("[data-testid=create-flow-btn]").should("exist") + cy.get("[data-testid=create-flow-btn]").click({ force: true }) + cy.get("[data-testid=flow-name-input]").should("exist") + cy.get("[data-testid=flow-name-input]").click({ force: true }).type("flow1") + cy.get("[data-testid=flow-color-FFCC00]").should("exist") + cy.get("[data-testid=flow-color-FFCC00]").click({ force: true }) + cy.wait(100) + cy.get("[data-testid=flow-save-btn").should("exist") + cy.get("[data-testid=flow-save-btn").click({ force: true }) + cy.get("[data-testid=flow1-edit-btn]").should("exist") + cy.get("[data-testid=flow1-edit-btn]").click({ force: true }) + cy.location("pathname").should("eq", "/app/flow/flow1") + cy.get("[data-testid=flow-page]").should("exist") + cy.get("[data-testid=nodes-collapse-btn]").click({ force: true }) + cy.wait(500) + cy.get("[data-testid=default_node-item]").should("exist") + let nodes: any[] = [] + cy.request("http://localhost:8000/api/v1/flows").then((response) => { + nodes = response.body.data.flows.find((flow) => flow.name === "flow1").data.nodes + console.log(nodes) + }) + const dataTransfer = new DataTransfer() + cy.get("[data-testid=default_node-item]").trigger("dragstart", { dataTransfer }) + cy.get("[data-testid=rf__wrapper]").trigger("drop", { dataTransfer }) + cy.get("[data-testid=defaultnode-add-condition-btn]").should("exist") + cy.get("[data-testid=defaultnode-add-condition-btn]").click({ force: true }) + cy.wait(300) + cy.get("[data-testid=python-condition-editor]").should("exist") + cy.get("[data-testid=python-condition-editor]").type('if False: print("hello")') + cy.get("[data-testid=save-condition-button]").should("exist").click({ force: true }) + cy.get("[data-testid=rf__wrapper]").trigger("keydown", { ctrlKey: true, key: "s" }) + cy.wait(500) + cy.get("[data-testid=build-btn]").should("exist") + cy.get("[data-testid=build-btn]").click() + cy.wait(4000) + cy.get("[data-testid=build-menu-open-btn]").should("exist") + cy.get("[data-testid=build-menu-open-btn]").click() + cy.wait(300) + cy.get("[data-testid=run-btn]").should("exist") + cy.get("[data-testid=run-btn]").click() + cy.wait(1000) + cy.get("[data-testid=chat-btn]").should("exist") + cy.get("[data-testid=chat-btn]").click() + cy.get("[data-testid=chat-input]").should("exist") + cy.get("[data-testid=chat-input]").click() + cy.get("[data-testid=chat-input]").type("hello") + cy.get("[data-testid=chat-send]").should("exist") + cy.get("[data-testid=chat-send]").click() + cy.wait(300) + cy.get("[data-testid=bot-message]").should("exist") + cy.wrap(null).then(() => { + let currNodes: any[] = [] + cy.request("http://localhost:8000/api/v1/flows").then((response) => { + currNodes = response.body.data.flows.find((flow) => flow.name === "flow1").data.nodes + expect(currNodes.length - 1).to.eq(nodes.length) + const node = cy.get(`#${currNodes[currNodes.length - 1].id}`) + node.should("exist") + node.click({ force: true }) + const deletebtn = cy.get("[data-testid=header-button-delete-node]") + deletebtn.should("exist") + deletebtn.click() + cy.request("http://localhost:8000/api/v1/flows").then((response) => { + currNodes = response.body.data.flows.find((flow) => flow.name === "flow1").data.nodes + expect(currNodes.length).to.eq(nodes.length) + }) + cy.visit("http://localhost:5173/app/home") + cy.get("[data-testid=flow1-delete-btn]").should("exist") + cy.get("[data-testid=flow1-delete-btn]").click({ force: true }) + cy.get("[data-testid=flow1-edit-btn]").should("not.exist") + }) + }) + }) +}) diff --git a/frontend/cypress/fixtures/example.json b/frontend/cypress/fixtures/example.json new file mode 100644 index 00000000..02e42543 --- /dev/null +++ b/frontend/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts new file mode 100644 index 00000000..698b01a4 --- /dev/null +++ b/frontend/cypress/support/commands.ts @@ -0,0 +1,37 @@ +/// +// *********************************************** +// This example commands.ts shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add('login', (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) +// +// declare global { +// namespace Cypress { +// interface Chainable { +// login(email: string, password: string): Chainable +// drag(subject: string, options?: Partial): Chainable +// dismiss(subject: string, options?: Partial): Chainable +// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable +// } +// } +// } \ No newline at end of file diff --git a/frontend/cypress/support/e2e.ts b/frontend/cypress/support/e2e.ts new file mode 100644 index 00000000..f80f74f8 --- /dev/null +++ b/frontend/cypress/support/e2e.ts @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/e2e.ts is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') \ No newline at end of file diff --git a/frontend/dockerfile b/frontend/dockerfile new file mode 100644 index 00000000..7c13de21 --- /dev/null +++ b/frontend/dockerfile @@ -0,0 +1,9 @@ +FROM oven/bun:1 as base +WORKDIR /app + +COPY package*.json ./ +COPY bun.lockb ./ + +RUN bun install + +COPY ./ ./ \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 00000000..bdebcbdc --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + DFD 0.1.0 + + +
+ + + diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 00000000..dedbac78 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,6715 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "dependencies": { + "@nextui-org/react": "^2.2.9", + "@react-spring/web": "^9.7.3", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@types/lodash": "^4.17.0", + "@types/uuid": "^9.0.8", + "@uidotdev/usehooks": "^2.4.1", + "axios": "^1.6.7", + "classnames": "^2.5.1", + "esbuild-wasm": "0.20.2", + "framer-motion": "^11.0.6", + "lodash": "^4.17.21", + "lucide-react": "^0.343.0", + "random-words": "^2.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-hot-toast": "^2.4.1", + "react-router-dom": "^6.22.2", + "reactflow": "^11.10.4", + "uuid": "^9.0.1" + }, + "devDependencies": { + "@types/react": "^18.2.56", + "@types/react-dom": "^18.2.19", + "@typescript-eslint/eslint-plugin": "^7.0.2", + "@typescript-eslint/parser": "^7.0.2", + "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.4.17", + "eslint": "^8.56.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.5", + "postcss": "^8.4.35", + "tailwindcss": "^3.4.1", + "typescript": "^5.2.2", + "vite": "^5.1.4" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk/node_modules/ansi-styles": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert": { + "version": "1.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/code-frame/node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk/node_modules/supports-color/node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.0", + "dev": true, + "license": "MIT", + "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.24.0", + "@babel/parser": "^7.24.0", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0", + "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/core/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.6", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache/node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "dev": true, + "license": "MIT", + "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.24.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "dev": true, + "license": "MIT", + "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/highlight/node_modules/chalk": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert": { + "version": "1.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.0", + "dev": true, + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.23.3", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "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.24.0", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.0", + "dev": true, + "license": "MIT", + "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.24.0", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "dev": true, + "license": "MIT", + "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/is-prop-valid": { + "version": "0.8.8", + "license": "MIT", + "optional": true, + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.4", + "license": "MIT", + "optional": true + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "1.18.2", + "license": "MIT", + "dependencies": { + "@formatjs/intl-localematcher": "0.5.4", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.7.6", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "1.18.2", + "@formatjs/icu-skeleton-parser": "1.8.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.0", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "1.18.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.5.4", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@internationalized/date": { + "version": "3.5.2", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@internationalized/message": { + "version": "3.1.2", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "intl-messageformat": "^10.1.0" + } + }, + "node_modules/@internationalized/number": { + "version": "3.5.1", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@internationalized/string": { + "version": "3.2.1", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@isaacs/cliui/node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi-cjs/node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.4", + "license": "MIT", + "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.2", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.23", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nextui-org/accordion": { + "version": "2.0.28", + "license": "MIT", + "dependencies": { + "@nextui-org/aria-utils": "2.0.15", + "@nextui-org/divider": "2.0.25", + "@nextui-org/framer-transitions": "2.0.15", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-icons": "2.0.6", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-aria-accordion": "2.0.2", + "@nextui-org/use-aria-press": "2.0.1", + "@react-aria/button": "^3.8.4", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/utils": "^3.21.1", + "@react-stately/tree": "^3.7.3", + "@react-types/accordion": "3.0.0-alpha.17", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/aria-utils": { + "version": "2.0.15", + "license": "MIT", + "dependencies": { + "@nextui-org/react-rsc-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/system": "2.0.15", + "@react-aria/utils": "^3.21.1", + "@react-stately/collections": "^3.10.2", + "@react-types/overlays": "^3.8.3", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/autocomplete": { + "version": "2.0.9", + "license": "MIT", + "dependencies": { + "@nextui-org/aria-utils": "2.0.15", + "@nextui-org/button": "2.0.26", + "@nextui-org/input": "2.1.16", + "@nextui-org/listbox": "2.1.16", + "@nextui-org/popover": "2.1.14", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/scroll-shadow": "2.1.12", + "@nextui-org/shared-icons": "2.0.6", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/spinner": "2.0.24", + "@nextui-org/use-aria-button": "2.0.6", + "@react-aria/combobox": "^3.7.1", + "@react-aria/focus": "^3.14.3", + "@react-aria/i18n": "^3.8.4", + "@react-aria/interactions": "^3.19.1", + "@react-aria/utils": "^3.21.1", + "@react-aria/visually-hidden": "^3.8.6", + "@react-stately/combobox": "^3.7.1", + "@react-types/combobox": "^3.8.1", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/avatar": { + "version": "2.0.24", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-image": "2.0.4", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/utils": "^3.21.1" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/badge": { + "version": "2.0.24", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/system-rsc": "2.0.11" + }, + "peerDependencies": { + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/breadcrumbs": { + "version": "2.0.4", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-icons": "2.0.6", + "@nextui-org/shared-utils": "2.0.4", + "@react-aria/breadcrumbs": "^3.5.7", + "@react-aria/focus": "^3.14.3", + "@react-aria/utils": "^3.21.1", + "@react-types/breadcrumbs": "^3.7.1", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/button": { + "version": "2.0.26", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/ripple": "2.0.24", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/spinner": "2.0.24", + "@nextui-org/use-aria-button": "2.0.6", + "@react-aria/button": "^3.8.4", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/utils": "^3.21.1", + "@react-types/button": "^3.9.0", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/card": { + "version": "2.0.24", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/ripple": "2.0.24", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-aria-button": "2.0.6", + "@react-aria/button": "^3.8.4", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/utils": "^3.21.1", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/checkbox": { + "version": "2.0.25", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-aria-press": "2.0.1", + "@react-aria/checkbox": "^3.11.2", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/utils": "^3.21.1", + "@react-aria/visually-hidden": "^3.8.6", + "@react-stately/checkbox": "^3.5.1", + "@react-stately/toggle": "^3.6.3", + "@react-types/checkbox": "^3.5.2", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/chip": { + "version": "2.0.25", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-icons": "2.0.6", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-aria-press": "2.0.1", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/utils": "^3.21.1", + "@react-types/checkbox": "^3.5.2" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/code": { + "version": "2.0.24", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/system-rsc": "2.0.11" + }, + "peerDependencies": { + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/divider": { + "version": "2.0.25", + "license": "MIT", + "dependencies": { + "@nextui-org/react-rsc-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/system-rsc": "2.0.11", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/dropdown": { + "version": "2.1.16", + "license": "MIT", + "dependencies": { + "@nextui-org/menu": "2.0.17", + "@nextui-org/popover": "2.1.14", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@react-aria/focus": "^3.14.3", + "@react-aria/menu": "^3.11.1", + "@react-aria/utils": "^3.21.1", + "@react-stately/menu": "^3.5.6", + "@react-types/menu": "^3.9.5" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/framer-transitions": { + "version": "2.0.15", + "license": "MIT", + "dependencies": { + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/system": "2.0.15" + }, + "peerDependencies": { + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/image": { + "version": "2.0.24", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-image": "2.0.4" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/input": { + "version": "2.1.16", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-icons": "2.0.6", + "@nextui-org/shared-utils": "2.0.4", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/textfield": "^3.12.2", + "@react-aria/utils": "^3.21.1", + "@react-stately/utils": "^3.8.0", + "@react-types/shared": "^3.21.0", + "@react-types/textfield": "^3.8.1", + "react-textarea-autosize": "^8.5.2" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/kbd": { + "version": "2.0.25", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/system-rsc": "2.0.11", + "@react-aria/utils": "^3.21.1" + }, + "peerDependencies": { + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/link": { + "version": "2.0.26", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-icons": "2.0.6", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-aria-link": "2.0.15", + "@react-aria/focus": "^3.14.3", + "@react-aria/link": "^3.6.1", + "@react-aria/utils": "^3.21.1", + "@react-types/link": "^3.5.1" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/listbox": { + "version": "2.1.16", + "license": "MIT", + "dependencies": { + "@nextui-org/aria-utils": "2.0.15", + "@nextui-org/divider": "2.0.25", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-aria-press": "2.0.1", + "@nextui-org/use-is-mobile": "2.0.6", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/listbox": "^3.11.1", + "@react-aria/utils": "^3.21.1", + "@react-stately/list": "^3.10.0", + "@react-types/menu": "^3.9.5", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/menu": { + "version": "2.0.17", + "license": "MIT", + "dependencies": { + "@nextui-org/aria-utils": "2.0.15", + "@nextui-org/divider": "2.0.25", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-aria-press": "2.0.1", + "@nextui-org/use-is-mobile": "2.0.6", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/menu": "^3.11.1", + "@react-aria/utils": "^3.21.1", + "@react-stately/menu": "^3.5.6", + "@react-stately/tree": "^3.7.3", + "@react-types/menu": "^3.9.5", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/modal": { + "version": "2.0.28", + "license": "MIT", + "dependencies": { + "@nextui-org/framer-transitions": "2.0.15", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-icons": "2.0.6", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-aria-button": "2.0.6", + "@nextui-org/use-aria-modal-overlay": "2.0.6", + "@nextui-org/use-disclosure": "2.0.6", + "@react-aria/dialog": "^3.5.7", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/overlays": "^3.18.1", + "@react-aria/utils": "^3.21.1", + "@react-stately/overlays": "^3.6.3", + "@react-types/overlays": "^3.8.3", + "react-remove-scroll": "^2.5.6" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/navbar": { + "version": "2.0.27", + "license": "MIT", + "dependencies": { + "@nextui-org/framer-transitions": "2.0.15", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-aria-toggle-button": "2.0.6", + "@nextui-org/use-scroll-position": "2.0.4", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/overlays": "^3.18.1", + "@react-aria/utils": "^3.21.1", + "@react-stately/toggle": "^3.6.3", + "@react-stately/utils": "^3.8.0", + "react-remove-scroll": "^2.5.6" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/pagination": { + "version": "2.0.26", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-icons": "2.0.6", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-aria-press": "2.0.1", + "@nextui-org/use-pagination": "2.0.4", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/utils": "^3.21.1", + "scroll-into-view-if-needed": "3.0.10" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/popover": { + "version": "2.1.14", + "license": "MIT", + "dependencies": { + "@nextui-org/aria-utils": "2.0.15", + "@nextui-org/button": "2.0.26", + "@nextui-org/framer-transitions": "2.0.15", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-aria-button": "2.0.6", + "@react-aria/dialog": "^3.5.7", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/overlays": "^3.18.1", + "@react-aria/utils": "^3.21.1", + "@react-stately/overlays": "^3.6.3", + "@react-types/button": "^3.9.0", + "@react-types/overlays": "^3.8.3", + "react-remove-scroll": "^2.5.6" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/progress": { + "version": "2.0.24", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-is-mounted": "2.0.4", + "@react-aria/i18n": "^3.8.4", + "@react-aria/progress": "^3.4.7", + "@react-aria/utils": "^3.21.1", + "@react-types/progress": "^3.5.0" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/radio": { + "version": "2.0.25", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-aria-press": "2.0.1", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/radio": "^3.8.2", + "@react-aria/utils": "^3.21.1", + "@react-aria/visually-hidden": "^3.8.6", + "@react-stately/radio": "^3.9.1", + "@react-types/radio": "^3.5.2", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/react": { + "version": "2.2.9", + "license": "MIT", + "dependencies": { + "@nextui-org/accordion": "2.0.28", + "@nextui-org/autocomplete": "2.0.9", + "@nextui-org/avatar": "2.0.24", + "@nextui-org/badge": "2.0.24", + "@nextui-org/breadcrumbs": "2.0.4", + "@nextui-org/button": "2.0.26", + "@nextui-org/card": "2.0.24", + "@nextui-org/checkbox": "2.0.25", + "@nextui-org/chip": "2.0.25", + "@nextui-org/code": "2.0.24", + "@nextui-org/divider": "2.0.25", + "@nextui-org/dropdown": "2.1.16", + "@nextui-org/image": "2.0.24", + "@nextui-org/input": "2.1.16", + "@nextui-org/kbd": "2.0.25", + "@nextui-org/link": "2.0.26", + "@nextui-org/listbox": "2.1.16", + "@nextui-org/menu": "2.0.17", + "@nextui-org/modal": "2.0.28", + "@nextui-org/navbar": "2.0.27", + "@nextui-org/pagination": "2.0.26", + "@nextui-org/popover": "2.1.14", + "@nextui-org/progress": "2.0.24", + "@nextui-org/radio": "2.0.25", + "@nextui-org/ripple": "2.0.24", + "@nextui-org/scroll-shadow": "2.1.12", + "@nextui-org/select": "2.1.20", + "@nextui-org/skeleton": "2.0.24", + "@nextui-org/slider": "2.2.5", + "@nextui-org/snippet": "2.0.30", + "@nextui-org/spacer": "2.0.24", + "@nextui-org/spinner": "2.0.24", + "@nextui-org/switch": "2.0.25", + "@nextui-org/system": "2.0.15", + "@nextui-org/table": "2.0.28", + "@nextui-org/tabs": "2.0.26", + "@nextui-org/theme": "2.1.17", + "@nextui-org/tooltip": "2.0.29", + "@nextui-org/user": "2.0.25", + "@react-aria/visually-hidden": "^3.8.6" + }, + "peerDependencies": { + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/react-rsc-utils": { + "version": "2.0.10", + "license": "MIT" + }, + "node_modules/@nextui-org/react-utils": { + "version": "2.0.10", + "license": "MIT", + "dependencies": { + "@nextui-org/react-rsc-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/ripple": { + "version": "2.0.24", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/scroll-shadow": { + "version": "2.1.12", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-data-scroll-overflow": "2.1.2" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/select": { + "version": "2.1.20", + "license": "MIT", + "dependencies": { + "@nextui-org/aria-utils": "2.0.15", + "@nextui-org/listbox": "2.1.16", + "@nextui-org/popover": "2.1.14", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/scroll-shadow": "2.1.12", + "@nextui-org/shared-icons": "2.0.6", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/spinner": "2.0.24", + "@nextui-org/use-aria-button": "2.0.6", + "@nextui-org/use-aria-multiselect": "2.1.3", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/utils": "^3.21.1", + "@react-aria/visually-hidden": "^3.8.6", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/shared-icons": { + "version": "2.0.6", + "license": "MIT", + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/shared-utils": { + "version": "2.0.4", + "license": "MIT", + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/skeleton": { + "version": "2.0.24", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/system-rsc": "2.0.11" + }, + "peerDependencies": { + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/slider": { + "version": "2.2.5", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/tooltip": "2.0.29", + "@nextui-org/use-aria-press": "2.0.1", + "@react-aria/focus": "^3.14.3", + "@react-aria/i18n": "^3.8.4", + "@react-aria/interactions": "^3.19.1", + "@react-aria/slider": "^3.7.2", + "@react-aria/utils": "^3.21.1", + "@react-aria/visually-hidden": "^3.8.6", + "@react-stately/slider": "^3.4.4" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/snippet": { + "version": "2.0.30", + "license": "MIT", + "dependencies": { + "@nextui-org/button": "2.0.26", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-icons": "2.0.6", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/tooltip": "2.0.29", + "@nextui-org/use-clipboard": "2.0.4", + "@react-aria/focus": "^3.14.3", + "@react-aria/utils": "^3.21.1" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/spacer": { + "version": "2.0.24", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/system-rsc": "2.0.11" + }, + "peerDependencies": { + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/spinner": { + "version": "2.0.24", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/system-rsc": "2.0.11" + }, + "peerDependencies": { + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/switch": { + "version": "2.0.25", + "license": "MIT", + "dependencies": { + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-aria-press": "2.0.1", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/switch": "^3.5.6", + "@react-aria/utils": "^3.21.1", + "@react-aria/visually-hidden": "^3.8.6", + "@react-stately/toggle": "^3.6.3", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/system": { + "version": "2.0.15", + "license": "MIT", + "dependencies": { + "@nextui-org/system-rsc": "2.0.11", + "@react-aria/i18n": "^3.8.4", + "@react-aria/overlays": "^3.18.1", + "@react-aria/utils": "^3.21.1", + "@react-stately/utils": "^3.8.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/system-rsc": { + "version": "2.0.11", + "license": "MIT", + "dependencies": { + "clsx": "^1.2.1" + }, + "peerDependencies": { + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "tailwind-variants": ">=0.1.13" + } + }, + "node_modules/@nextui-org/system-rsc/node_modules/clsx": { + "version": "1.2.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@nextui-org/table": { + "version": "2.0.28", + "license": "MIT", + "dependencies": { + "@nextui-org/checkbox": "2.0.25", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-icons": "2.0.6", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/spacer": "2.0.24", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/table": "^3.13.1", + "@react-aria/utils": "^3.21.1", + "@react-aria/visually-hidden": "^3.8.6", + "@react-stately/table": "^3.11.2", + "@react-stately/virtualizer": "^3.6.4", + "@react-types/grid": "^3.2.2", + "@react-types/table": "^3.9.0" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/tabs": { + "version": "2.0.26", + "license": "MIT", + "dependencies": { + "@nextui-org/aria-utils": "2.0.15", + "@nextui-org/framer-transitions": "2.0.15", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@nextui-org/use-is-mounted": "2.0.4", + "@nextui-org/use-update-effect": "2.0.4", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/tabs": "^3.8.1", + "@react-aria/utils": "^3.21.1", + "@react-stately/tabs": "^3.6.1", + "@react-types/shared": "^3.21.0", + "@react-types/tabs": "^3.3.3", + "scroll-into-view-if-needed": "3.0.10" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/theme": { + "version": "2.1.17", + "license": "MIT", + "dependencies": { + "color": "^4.2.3", + "color2k": "^2.0.2", + "deepmerge": "4.3.1", + "flat": "^5.0.2", + "lodash.foreach": "^4.5.0", + "lodash.get": "^4.4.2", + "lodash.kebabcase": "^4.1.1", + "lodash.mapkeys": "^4.6.0", + "lodash.omit": "^4.5.0", + "tailwind-variants": "^0.1.18" + }, + "peerDependencies": { + "tailwindcss": "*" + } + }, + "node_modules/@nextui-org/tooltip": { + "version": "2.0.29", + "license": "MIT", + "dependencies": { + "@nextui-org/aria-utils": "2.0.15", + "@nextui-org/framer-transitions": "2.0.15", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@react-aria/interactions": "^3.19.1", + "@react-aria/overlays": "^3.18.1", + "@react-aria/tooltip": "^3.6.4", + "@react-aria/utils": "^3.21.1", + "@react-stately/tooltip": "^3.4.5", + "@react-types/overlays": "^3.8.3", + "@react-types/tooltip": "^3.4.5" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "framer-motion": ">=4.0.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/use-aria-accordion": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "@react-aria/button": "^3.8.4", + "@react-aria/focus": "^3.14.3", + "@react-aria/selection": "^3.17.1", + "@react-aria/utils": "^3.21.1", + "@react-stately/tree": "^3.7.3", + "@react-types/accordion": "3.0.0-alpha.17", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-aria-button": { + "version": "2.0.6", + "license": "MIT", + "dependencies": { + "@nextui-org/use-aria-press": "2.0.1", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/utils": "^3.21.1", + "@react-types/button": "^3.9.0", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-aria-link": { + "version": "2.0.15", + "license": "MIT", + "dependencies": { + "@nextui-org/use-aria-press": "2.0.1", + "@react-aria/focus": "^3.14.3", + "@react-aria/interactions": "^3.19.1", + "@react-aria/utils": "^3.21.1", + "@react-types/link": "^3.5.1", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-aria-modal-overlay": { + "version": "2.0.6", + "license": "MIT", + "dependencies": { + "@react-aria/overlays": "^3.18.1", + "@react-aria/utils": "^3.21.1", + "@react-stately/overlays": "^3.6.3", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/use-aria-multiselect": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@react-aria/i18n": "^3.8.4", + "@react-aria/interactions": "^3.19.1", + "@react-aria/label": "^3.7.2", + "@react-aria/listbox": "^3.11.1", + "@react-aria/menu": "^3.11.1", + "@react-aria/selection": "^3.17.1", + "@react-aria/utils": "^3.21.1", + "@react-stately/list": "^3.10.0", + "@react-stately/menu": "^3.5.6", + "@react-types/button": "^3.9.0", + "@react-types/overlays": "^3.8.3", + "@react-types/select": "^3.8.4", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nextui-org/use-aria-press": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "@react-aria/interactions": "^3.19.1", + "@react-aria/ssr": "^3.8.0", + "@react-aria/utils": "^3.21.1", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-aria-toggle-button": { + "version": "2.0.6", + "license": "MIT", + "dependencies": { + "@nextui-org/use-aria-button": "2.0.6", + "@react-aria/utils": "^3.21.1", + "@react-stately/toggle": "^3.6.3", + "@react-types/button": "^3.9.0", + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-callback-ref": { + "version": "2.0.4", + "license": "MIT", + "dependencies": { + "@nextui-org/use-safe-layout-effect": "2.0.4" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-clipboard": { + "version": "2.0.4", + "license": "MIT", + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-data-scroll-overflow": { + "version": "2.1.2", + "license": "MIT", + "dependencies": { + "@nextui-org/shared-utils": "2.0.4" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-disclosure": { + "version": "2.0.6", + "license": "MIT", + "dependencies": { + "@nextui-org/use-callback-ref": "2.0.4", + "@react-aria/utils": "^3.21.1", + "@react-stately/utils": "^3.8.0" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-image": { + "version": "2.0.4", + "license": "MIT", + "dependencies": { + "@nextui-org/use-safe-layout-effect": "2.0.4" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-is-mobile": { + "version": "2.0.6", + "license": "MIT", + "dependencies": { + "@react-aria/ssr": "^3.8.0" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-is-mounted": { + "version": "2.0.4", + "license": "MIT", + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-pagination": { + "version": "2.0.4", + "license": "MIT", + "dependencies": { + "@nextui-org/shared-utils": "2.0.4" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-safe-layout-effect": { + "version": "2.0.4", + "license": "MIT", + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-scroll-position": { + "version": "2.0.4", + "license": "MIT", + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/use-update-effect": { + "version": "2.0.4", + "license": "MIT", + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@nextui-org/user": { + "version": "2.0.25", + "license": "MIT", + "dependencies": { + "@nextui-org/avatar": "2.0.24", + "@nextui-org/react-utils": "2.0.10", + "@nextui-org/shared-utils": "2.0.4", + "@react-aria/focus": "^3.14.3", + "@react-aria/utils": "^3.21.1" + }, + "peerDependencies": { + "@nextui-org/system": ">=2.0.0", + "@nextui-org/theme": ">=2.1.0", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@react-aria/breadcrumbs": { + "version": "3.5.11", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/i18n": "^3.10.2", + "@react-aria/link": "^3.6.5", + "@react-aria/utils": "^3.23.2", + "@react-types/breadcrumbs": "^3.7.3", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/button": { + "version": "3.9.3", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/utils": "^3.23.2", + "@react-stately/toggle": "^3.7.2", + "@react-types/button": "^3.9.2", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/checkbox": { + "version": "3.14.1", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/form": "^3.0.3", + "@react-aria/interactions": "^3.21.1", + "@react-aria/label": "^3.7.6", + "@react-aria/toggle": "^3.10.2", + "@react-aria/utils": "^3.23.2", + "@react-stately/checkbox": "^3.6.3", + "@react-stately/form": "^3.0.1", + "@react-stately/toggle": "^3.7.2", + "@react-types/checkbox": "^3.7.1", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/combobox": { + "version": "3.8.4", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/i18n": "^3.10.2", + "@react-aria/listbox": "^3.11.5", + "@react-aria/live-announcer": "^3.3.2", + "@react-aria/menu": "^3.13.1", + "@react-aria/overlays": "^3.21.1", + "@react-aria/selection": "^3.17.5", + "@react-aria/textfield": "^3.14.3", + "@react-aria/utils": "^3.23.2", + "@react-stately/collections": "^3.10.5", + "@react-stately/combobox": "^3.8.2", + "@react-stately/form": "^3.0.1", + "@react-types/button": "^3.9.2", + "@react-types/combobox": "^3.10.1", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/dialog": { + "version": "3.5.12", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/overlays": "^3.21.1", + "@react-aria/utils": "^3.23.2", + "@react-types/dialog": "^3.5.8", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/focus": { + "version": "3.16.2", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.21.1", + "@react-aria/utils": "^3.23.2", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/form": { + "version": "3.0.3", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.21.1", + "@react-aria/utils": "^3.23.2", + "@react-stately/form": "^3.0.1", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/grid": { + "version": "3.8.8", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/i18n": "^3.10.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/live-announcer": "^3.3.2", + "@react-aria/selection": "^3.17.5", + "@react-aria/utils": "^3.23.2", + "@react-stately/collections": "^3.10.5", + "@react-stately/grid": "^3.8.5", + "@react-stately/selection": "^3.14.3", + "@react-stately/virtualizer": "^3.6.8", + "@react-types/checkbox": "^3.7.1", + "@react-types/grid": "^3.2.4", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/i18n": { + "version": "3.10.2", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.5.2", + "@internationalized/message": "^3.1.2", + "@internationalized/number": "^3.5.1", + "@internationalized/string": "^3.2.1", + "@react-aria/ssr": "^3.9.2", + "@react-aria/utils": "^3.23.2", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/interactions": { + "version": "3.21.1", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.2", + "@react-aria/utils": "^3.23.2", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/label": { + "version": "3.7.6", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/utils": "^3.23.2", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/link": { + "version": "3.6.5", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/utils": "^3.23.2", + "@react-types/link": "^3.5.3", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/listbox": { + "version": "3.11.5", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.21.1", + "@react-aria/label": "^3.7.6", + "@react-aria/selection": "^3.17.5", + "@react-aria/utils": "^3.23.2", + "@react-stately/collections": "^3.10.5", + "@react-stately/list": "^3.10.3", + "@react-types/listbox": "^3.4.7", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/live-announcer": { + "version": "3.3.2", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@react-aria/menu": { + "version": "3.13.1", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/i18n": "^3.10.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/overlays": "^3.21.1", + "@react-aria/selection": "^3.17.5", + "@react-aria/utils": "^3.23.2", + "@react-stately/collections": "^3.10.5", + "@react-stately/menu": "^3.6.1", + "@react-stately/tree": "^3.7.6", + "@react-types/button": "^3.9.2", + "@react-types/menu": "^3.9.7", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/overlays": { + "version": "3.21.1", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/i18n": "^3.10.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/ssr": "^3.9.2", + "@react-aria/utils": "^3.23.2", + "@react-aria/visually-hidden": "^3.8.10", + "@react-stately/overlays": "^3.6.5", + "@react-types/button": "^3.9.2", + "@react-types/overlays": "^3.8.5", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/progress": { + "version": "3.4.11", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/i18n": "^3.10.2", + "@react-aria/label": "^3.7.6", + "@react-aria/utils": "^3.23.2", + "@react-types/progress": "^3.5.2", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/radio": { + "version": "3.10.2", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/form": "^3.0.3", + "@react-aria/i18n": "^3.10.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/label": "^3.7.6", + "@react-aria/utils": "^3.23.2", + "@react-stately/radio": "^3.10.2", + "@react-types/radio": "^3.7.1", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/selection": { + "version": "3.17.5", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/i18n": "^3.10.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/utils": "^3.23.2", + "@react-stately/selection": "^3.14.3", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/slider": { + "version": "3.7.6", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/i18n": "^3.10.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/label": "^3.7.6", + "@react-aria/utils": "^3.23.2", + "@react-stately/slider": "^3.5.2", + "@react-types/shared": "^3.22.1", + "@react-types/slider": "^3.7.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.9.2", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/switch": { + "version": "3.6.2", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/toggle": "^3.10.2", + "@react-stately/toggle": "^3.7.2", + "@react-types/switch": "^3.5.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/table": { + "version": "3.13.5", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/grid": "^3.8.8", + "@react-aria/i18n": "^3.10.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/live-announcer": "^3.3.2", + "@react-aria/utils": "^3.23.2", + "@react-aria/visually-hidden": "^3.8.10", + "@react-stately/collections": "^3.10.5", + "@react-stately/flags": "^3.0.1", + "@react-stately/table": "^3.11.6", + "@react-stately/virtualizer": "^3.6.8", + "@react-types/checkbox": "^3.7.1", + "@react-types/grid": "^3.2.4", + "@react-types/shared": "^3.22.1", + "@react-types/table": "^3.9.3", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/tabs": { + "version": "3.8.5", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/i18n": "^3.10.2", + "@react-aria/selection": "^3.17.5", + "@react-aria/utils": "^3.23.2", + "@react-stately/tabs": "^3.6.4", + "@react-types/shared": "^3.22.1", + "@react-types/tabs": "^3.3.5", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/textfield": { + "version": "3.14.3", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/form": "^3.0.3", + "@react-aria/label": "^3.7.6", + "@react-aria/utils": "^3.23.2", + "@react-stately/form": "^3.0.1", + "@react-stately/utils": "^3.9.1", + "@react-types/shared": "^3.22.1", + "@react-types/textfield": "^3.9.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/toggle": { + "version": "3.10.2", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/utils": "^3.23.2", + "@react-stately/toggle": "^3.7.2", + "@react-types/checkbox": "^3.7.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/tooltip": { + "version": "3.7.2", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.16.2", + "@react-aria/interactions": "^3.21.1", + "@react-aria/utils": "^3.23.2", + "@react-stately/tooltip": "^3.4.7", + "@react-types/shared": "^3.22.1", + "@react-types/tooltip": "^3.4.7", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/utils": { + "version": "3.23.2", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.2", + "@react-stately/utils": "^3.9.1", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/visually-hidden": { + "version": "3.8.10", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.21.1", + "@react-aria/utils": "^3.23.2", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-spring/animated": { + "version": "9.7.3", + "license": "MIT", + "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", + "license": "MIT", + "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", + "license": "MIT", + "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", + "license": "MIT" + }, + "node_modules/@react-spring/web": { + "version": "9.7.3", + "license": "MIT", + "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/@react-stately/checkbox": { + "version": "3.6.3", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/form": "^3.0.1", + "@react-stately/utils": "^3.9.1", + "@react-types/checkbox": "^3.7.1", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/collections": { + "version": "3.10.5", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/combobox": { + "version": "3.8.2", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/collections": "^3.10.5", + "@react-stately/form": "^3.0.1", + "@react-stately/list": "^3.10.3", + "@react-stately/overlays": "^3.6.5", + "@react-stately/select": "^3.6.2", + "@react-stately/utils": "^3.9.1", + "@react-types/combobox": "^3.10.1", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/flags": { + "version": "3.0.1", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.4.14" + } + }, + "node_modules/@react-stately/flags/node_modules/@swc/helpers": { + "version": "0.4.36", + "license": "Apache-2.0", + "dependencies": { + "legacy-swc-helpers": "npm:@swc/helpers@=0.4.14", + "tslib": "^2.4.0" + } + }, + "node_modules/@react-stately/flags/node_modules/@swc/helpers/node_modules/legacy-swc-helpers": { + "name": "@swc/helpers", + "version": "0.4.14", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@react-stately/form": { + "version": "3.0.1", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/grid": { + "version": "3.8.5", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/collections": "^3.10.5", + "@react-stately/selection": "^3.14.3", + "@react-types/grid": "^3.2.4", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/list": { + "version": "3.10.3", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/collections": "^3.10.5", + "@react-stately/selection": "^3.14.3", + "@react-stately/utils": "^3.9.1", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/menu": { + "version": "3.6.1", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/overlays": "^3.6.5", + "@react-types/menu": "^3.9.7", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/overlays": { + "version": "3.6.5", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/utils": "^3.9.1", + "@react-types/overlays": "^3.8.5", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/radio": { + "version": "3.10.2", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/form": "^3.0.1", + "@react-stately/utils": "^3.9.1", + "@react-types/radio": "^3.7.1", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/select": { + "version": "3.6.2", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/form": "^3.0.1", + "@react-stately/list": "^3.10.3", + "@react-stately/overlays": "^3.6.5", + "@react-types/select": "^3.9.2", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/selection": { + "version": "3.14.3", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/collections": "^3.10.5", + "@react-stately/utils": "^3.9.1", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/slider": { + "version": "3.5.2", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/utils": "^3.9.1", + "@react-types/shared": "^3.22.1", + "@react-types/slider": "^3.7.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/table": { + "version": "3.11.6", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/collections": "^3.10.5", + "@react-stately/flags": "^3.0.1", + "@react-stately/grid": "^3.8.5", + "@react-stately/selection": "^3.14.3", + "@react-stately/utils": "^3.9.1", + "@react-types/grid": "^3.2.4", + "@react-types/shared": "^3.22.1", + "@react-types/table": "^3.9.3", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/tabs": { + "version": "3.6.4", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/list": "^3.10.3", + "@react-types/shared": "^3.22.1", + "@react-types/tabs": "^3.3.5", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/toggle": { + "version": "3.7.2", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/utils": "^3.9.1", + "@react-types/checkbox": "^3.7.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/tooltip": { + "version": "3.4.7", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/overlays": "^3.6.5", + "@react-types/tooltip": "^3.4.7", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/tree": { + "version": "3.7.6", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/collections": "^3.10.5", + "@react-stately/selection": "^3.14.3", + "@react-stately/utils": "^3.9.1", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/utils": { + "version": "3.9.1", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/virtualizer": { + "version": "3.6.8", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/utils": "^3.23.2", + "@react-types/shared": "^3.22.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/accordion": { + "version": "3.0.0-alpha.17", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.21.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/breadcrumbs": { + "version": "3.7.3", + "license": "Apache-2.0", + "dependencies": { + "@react-types/link": "^3.5.3", + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/button": { + "version": "3.9.2", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/checkbox": { + "version": "3.7.1", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/combobox": { + "version": "3.10.1", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/dialog": { + "version": "3.5.8", + "license": "Apache-2.0", + "dependencies": { + "@react-types/overlays": "^3.8.5", + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/grid": { + "version": "3.2.4", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/link": { + "version": "3.5.3", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/listbox": { + "version": "3.4.7", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/menu": { + "version": "3.9.7", + "license": "Apache-2.0", + "dependencies": { + "@react-types/overlays": "^3.8.5", + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/overlays": { + "version": "3.8.5", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/progress": { + "version": "3.5.2", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/radio": { + "version": "3.7.1", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/select": { + "version": "3.9.2", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/shared": { + "version": "3.22.1", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/slider": { + "version": "3.7.1", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/switch": { + "version": "3.5.1", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/table": { + "version": "3.9.3", + "license": "Apache-2.0", + "dependencies": { + "@react-types/grid": "^3.2.4", + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/tabs": { + "version": "3.3.5", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/textfield": { + "version": "3.9.1", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/tooltip": { + "version": "3.4.7", + "license": "Apache-2.0", + "dependencies": { + "@react-types/overlays": "^3.8.5", + "@react-types/shared": "^3.22.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@reactflow/background": { + "version": "11.3.9", + "license": "MIT", + "dependencies": { + "@reactflow/core": "11.10.4", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/controls": { + "version": "11.2.9", + "license": "MIT", + "dependencies": { + "@reactflow/core": "11.10.4", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/core": { + "version": "11.10.4", + "license": "MIT", + "dependencies": { + "@types/d3": "^7.4.0", + "@types/d3-drag": "^3.0.1", + "@types/d3-selection": "^3.0.3", + "@types/d3-zoom": "^3.0.1", + "classcat": "^5.0.3", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/minimap": { + "version": "11.7.9", + "license": "MIT", + "dependencies": { + "@reactflow/core": "11.10.4", + "@types/d3-selection": "^3.0.3", + "@types/d3-zoom": "^3.0.1", + "classcat": "^5.0.3", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/node-resizer": { + "version": "2.2.9", + "license": "MIT", + "dependencies": { + "@reactflow/core": "11.10.4", + "classcat": "^5.0.4", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/node-toolbar": { + "version": "1.3.9", + "license": "MIT", + "dependencies": { + "@reactflow/core": "11.10.4", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@remix-run/router": { + "version": "1.15.2", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz", + "integrity": "sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.0.tgz", + "integrity": "sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.12.0", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.0.tgz", + "integrity": "sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.0.tgz", + "integrity": "sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", + "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", + "cpu": [ + "arm64" + ], + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.0.tgz", + "integrity": "sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.0.tgz", + "integrity": "sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz", + "integrity": "sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.0.tgz", + "integrity": "sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.0.tgz", + "integrity": "sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.0.tgz", + "integrity": "sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz", + "integrity": "sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@swc/helpers": { + "version": "0.5.6", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "dev": true, + "license": "MIT", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.6", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.9", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.6", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.0", + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.10", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.8", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.14", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.0", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.11", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.2.60", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.19", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.8", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/type-utils": "7.1.0", + "@typescript-eslint/utils": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.1.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/utils": "7.1.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.1.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.1.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@uidotdev/usehooks": { + "version": "2.4.1", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.2.1", + "dev": true, + "license": "MIT", + "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/acorn": { + "version": "8.11.3", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "license": "MIT" + }, + "node_modules/autoprefixer": { + "version": "10.4.17", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.22.2", + "caniuse-lite": "^1.0.30001578", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axios": { + "version": "1.6.7", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "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" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "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/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001591", + "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" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/classcat": { + "version": "5.0.4", + "license": "MIT" + }, + "node_modules/classnames": { + "version": "2.5.1", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color2k": { + "version": "2.0.3", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.0", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/d3-color": { + "version": "3.1.0", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "license": "Apache-2.0" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "3.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.685", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.19.12", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.20.2.tgz", + "integrity": "sha512-7o6nmsEqlcXJXMNqnx5K+M4w4OPx7yTFXQHcJyeP3SkXb8p2T8N9E1ayK4vd/qDBepH6fuPoZwiFvZm8x5qv+w==", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.5", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=7" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/framer-motion": { + "version": "11.0.6", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "optionalDependencies": { + "@emotion/is-prop-valid": "^0.8.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "10.3.10", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.3", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/goober": { + "version": "2.1.14", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/intl-messageformat": { + "version": "10.5.11", + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/ecma402-abstract": "1.18.2", + "@formatjs/fast-memoize": "2.2.0", + "@formatjs/icu-messageformat-parser": "2.7.6", + "tslib": "^2.4.0" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "license": "MIT" + }, + "node_modules/lodash.foreach": { + "version": "4.5.0", + "license": "MIT" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "license": "MIT" + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "license": "MIT" + }, + "node_modules/lodash.mapkeys": { + "version": "4.6.0", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.omit": { + "version": "4.5.0", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lucide-react": { + "version": "0.343.0", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.14", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.4.35", + "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" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.15", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/random-words": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "seedrandom": "^3.0.5" + } + }, + "node_modules/react": { + "version": "18.2.0", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-hot-toast": { + "version": "2.4.1", + "license": "MIT", + "dependencies": { + "goober": "^2.1.10" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.5.7", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.4", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.5", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-router": { + "version": "6.22.2", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.15.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.22.2", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.15.2", + "react-router": "6.22.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.1", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "invariant": "^2.2.4", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-textarea-autosize": { + "version": "8.5.3", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.13", + "use-composed-ref": "^1.3.0", + "use-latest": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/reactflow": { + "version": "11.10.4", + "license": "MIT", + "dependencies": { + "@reactflow/background": "11.3.9", + "@reactflow/controls": "11.2.9", + "@reactflow/core": "11.10.4", + "@reactflow/minimap": "11.7.9", + "@reactflow/node-resizer": "2.2.9", + "@reactflow/node-toolbar": "1.3.9" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.8", + "license": "MIT", + "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/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.12.0", + "@rollup/rollup-android-arm64": "4.12.0", + "@rollup/rollup-darwin-arm64": "4.12.0", + "@rollup/rollup-darwin-x64": "4.12.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.12.0", + "@rollup/rollup-linux-arm64-gnu": "4.12.0", + "@rollup/rollup-linux-arm64-musl": "4.12.0", + "@rollup/rollup-linux-riscv64-gnu": "4.12.0", + "@rollup/rollup-linux-x64-gnu": "4.12.0", + "@rollup/rollup-linux-x64-musl": "4.12.0", + "@rollup/rollup-win32-arm64-msvc": "4.12.0", + "@rollup/rollup-win32-ia32-msvc": "4.12.0", + "@rollup/rollup-win32-x64-msvc": "4.12.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.0.tgz", + "integrity": "sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/scroll-into-view-if-needed": { + "version": "3.0.10", + "license": "MIT", + "dependencies": { + "compute-scroll-into-view": "^3.0.2" + } + }, + "node_modules/seedrandom": { + "version": "3.0.5", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.6.0", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwind-merge": { + "version": "1.14.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwind-variants": { + "version": "0.1.20", + "license": "MIT", + "dependencies": { + "tailwind-merge": "^1.14.0" + }, + "engines": { + "node": ">=16.x", + "pnpm": ">=7.x" + }, + "peerDependencies": { + "tailwindcss": "*" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.1", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "2.6.2", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.3.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "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" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.1", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-composed-ref": { + "version": "1.3.0", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-latest": { + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "use-isomorphic-layout-effect": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.2", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "9.0.1", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vite": { + "version": "5.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.19.3", + "postcss": "^8.4.35", + "rollup": "^4.2.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "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/which": { + "version": "2.0.2", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.4.0", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zustand": { + "version": "4.5.1", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 00000000..adb7769b --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,89 @@ +{ + "name": "frontend", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview", + "test": "jest", + "e2e": "cypress run", + "e2e:headed": "cypress run --headed", + "e2e:chrome": "cypress run --browser chrome" + }, + "jest": { + "transform": { + "^.+\\.tsx?$": "ts-jest" + }, + "moduleNameMapper": { + "\\.(css|less)$": "identity-obj-proxy" + }, + "testEnvironment": "jsdom" + }, + "dependencies": { + "@babel/preset-env": "^7.24.5", + "@babel/preset-react": "^7.24.1", + "@babel/preset-typescript": "^7.24.1", + "@codemirror/lang-python": "^6.1.5", + "@jest/globals": "^29.7.0", + "@nextui-org/react": "^2.2.9", + "@playwright/test": "^1.43.1", + "@radix-ui/react-context-menu": "^2.1.5", + "@react-spring/web": "^9.7.3", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@testing-library/jest-dom": "^6.4.5", + "@testing-library/react": "^15.0.6", + "@testing-library/user-event": "^14.5.2", + "@uidotdev/usehooks": "^2.4.1", + "@uiw/codemirror-theme-andromeda": "^4.21.25", + "@uiw/codemirror-theme-noctis-lilac": "^4.21.25", + "@uiw/react-codemirror": "^4.21.25", + "axios": "^1.6.7", + "babel-jest": "^29.7.0", + "classnames": "^2.5.1", + "esbuild-wasm": "0.20.2", + "framer-motion": "^11.0.6", + "identity-obj-proxy": "^3.0.0", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "jest-fetch-mock": "^3.0.3", + "jsdom": "^24.0.0", + "lodash": "^4.17.21", + "lucide-react": "^0.343.0", + "random-words": "^2.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-hot-toast": "^2.4.1", + "react-intersection-observer": "^9.8.1", + "react-router-dom": "^6.22.2", + "react-test-renderer": "^18.3.1", + "react-xarrows": "^2.0.2", + "reactflow": "^11.10.4", + "ts-jest": "^29.1.2", + "ts-node": "^10.9.2", + "uuid": "^9.0.1", + "yaml": "^2.4.1" + }, + "devDependencies": { + "@types/jest": "^29.5.12", + "@types/lodash": "^4.17.0", + "@types/react": "^18.3.1", + "@types/react-dom": "^18.3.0", + "@types/uuid": "^9.0.8", + "@typescript-eslint/eslint-plugin": "^7.0.2", + "@typescript-eslint/parser": "^7.0.2", + "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.4.17", + "eslint": "^8.56.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.5", + "postcss": "^8.4.35", + "tailwindcss": "^3.4.1", + "typescript": "^5.2.2", + "vite": "^5.2.11", + "@types/bun": "latest" + }, + "module": "index.ts" +} \ No newline at end of file diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js new file mode 100644 index 00000000..2e7af2b7 --- /dev/null +++ b/frontend/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/frontend/public/Inter-VariableFont_slnt,wght.ttf b/frontend/public/Inter-VariableFont_slnt,wght.ttf new file mode 100644 index 00000000..ec3164ef Binary files /dev/null and b/frontend/public/Inter-VariableFont_slnt,wght.ttf differ diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 00000000..2833de99 Binary files /dev/null and b/frontend/public/favicon.ico differ diff --git a/frontend/src/App.css b/frontend/src/App.css new file mode 100644 index 00000000..e69de29b diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx new file mode 100644 index 00000000..b8684ca6 --- /dev/null +++ b/frontend/src/App.tsx @@ -0,0 +1,48 @@ +import { NextUIProvider } from "@nextui-org/react" +import { RouterProvider, createBrowserRouter } from "react-router-dom" +import { ReactFlowProvider } from "reactflow" +import { Preloader } from "./UI/Preloader/Preloader" +import ContextWrapper from "./contexts" +import { UndoRedoProvider } from "./contexts/undoRedoContext" +import Fallback from "./pages/Fallback" +import Flow from "./pages/Flow" +import Home from "./pages/Home" +import Index from "./pages/Index" + +const App = () => { + + const router = createBrowserRouter([ + { + path: "/", + element: ( + + + + ), + loader: Preloader, + errorElement: , + children: [ + { + path: "app/flow/:flowId", + element: ( + + + + + + ), + loader: Preloader, + }, + { path: "app/home", element: , loader: Preloader }, + ], + }, + ]) + + return ( + + + + ) +} + +export default App diff --git a/frontend/src/UI/Preloader/Preloader.tsx b/frontend/src/UI/Preloader/Preloader.tsx new file mode 100644 index 00000000..4e411bc1 --- /dev/null +++ b/frontend/src/UI/Preloader/Preloader.tsx @@ -0,0 +1,15 @@ +import React from 'react' +import './preloader.css' + +export const Preloader = () => { + return ( +
+ {/* //
+ //
+ //
*/} + + +
+ + ) +} diff --git a/frontend/src/UI/Preloader/preloader.css b/frontend/src/UI/Preloader/preloader.css new file mode 100644 index 00000000..9ece2d71 --- /dev/null +++ b/frontend/src/UI/Preloader/preloader.css @@ -0,0 +1,163 @@ +#preloader-wrapper { + background-color: hsl(var(--background)); + position: absolute; + z-index: 99; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +/* #preloader { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + scale: 0.5; +} +#loader { + display: block; + position: relative; + left: 50%; + top: 50%; + width: 150px; + height: 150px; + margin: -75px 0 0 -75px; + border-radius: 50%; + border: 6px solid transparent; + border-top-color: #70db97; + -webkit-animation: spin 2s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; + animation: spin 2s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; +} +#loader:before { + content: ""; + position: absolute; + top: 5px; + left: 5px; + right: 5px; + bottom: 5px; + border-radius: 50%; + border: 6px solid transparent; + border-top-color: #2036ff; + -webkit-animation: spin 3s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; + animation: spin 3s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; +} +#loader:after { + content: ""; + position: absolute; + top: 15px; + left: 15px; + right: 15px; + bottom: 15px; + border-radius: 50%; + border: 6px solid transparent; + border-top-color: #077ac9; + -webkit-animation: spin 1.5s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; + animation: spin 1.5s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@-webkit-keyframes spin-reverse { + 0% { + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(-360deg); + -ms-transform: rotate(-360deg); + transform: rotate(-360deg); + } +} +@keyframes spin-reverse { + 0% { + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(-360deg); + -ms-transform: rotate(-360deg); + transform: rotate(-360deg); + } +} */ + +.loader { + position: relative; + width: 120px; + height: 90px; + margin: 0 auto; +} +.loader:before { + content: ""; + position: absolute; + bottom: 30px; + left: 50px; + height: 30px; + width: 30px; + border-radius: 50%; + background: #27ff76; + animation: loading-bounce 0.5s ease-in-out infinite alternate; +} +.loader:after { + content: ""; + position: absolute; + right: 0; + top: 0; + height: 7px; + width: 45px; + border-radius: 4px; + box-shadow: 0 5px 0 #077ac9, -35px 50px 0 #077ac9, -70px 95px 0 #077ac9; + animation: loading-step 1s ease-in-out infinite; +} + +@keyframes loading-bounce { + 0% { + transform: scale(1, 0.7); + } + 40% { + transform: scale(0.8, 1.2); + } + 60% { + transform: scale(1, 1); + } + 100% { + bottom: 140px; + } +} +@keyframes loading-step { + 0% { + box-shadow: 0 10px 0 rgba(0, 0, 0, 0), 0 10px 0 #077ac9, -35px 50px 0 #077ac9, + -70px 90px 0 #077ac9; + } + 100% { + box-shadow: 0 10px 0 #077ac9, -35px 50px 0 #077ac9, -70px 90px 0 #077ac9, + -70px 90px 0 rgba(0, 0, 0, 0); + } +} diff --git a/frontend/src/api/bot.ts b/frontend/src/api/bot.ts new file mode 100644 index 00000000..f8690f09 --- /dev/null +++ b/frontend/src/api/bot.ts @@ -0,0 +1,200 @@ +import { $v1 } from "." + +export type buildApiStatusType = + | "completed" + | "failed" + | "running" + | "stopped" + | "success" + | "alive" + +type buildStartResponseType = { + status: "ok" | "error" + build_id: number +} + +type runStartResponseType = { + data: { + status: "ok" | "error" + run_id: number + } +} + +export type buildMinifyApiType = { + id: number + status: buildApiStatusType + preset_end_status: string + timestamp: number + runs: runMinifyApiType[] +} + +export type runMinifyApiType = { + id: number + status: buildApiStatusType + preset_end_status: string + log_path: string + timestamp: number + build_id: number +} + +export type buildPresetType = { + wait_time: number + end_status: buildApiStatusType +} + +export type buildResponseType = { + status?: string + build_id: number +} + +export type runApiType = { + id: number + status: buildApiStatusType + timestamp: number + preset_end_status: string + build_id: number + logs?: string[] + logs_path?: string +} + +export interface localRunType extends runMinifyApiType { + type: "run" +} + +export type buildApiType = { + id: number + status: buildApiStatusType + log_path?: string + logs?: string[] + preset_end_status: string + timestamp: number + runs: localRunType[] +} + +export interface localBuildType extends buildMinifyApiType { + type: "build" +} + +// type buildsResponseType = buildApiType[] +// // { +// // status?: string +// // build: buildApiType[] +// // } + +// type runsResponseType = { +// status?: string +// run: runApiType[] +// } + +// type runResponseType = { +// status?: string +// run_info: runApiType +// } + +type buildStatusResponseType = { + status: buildApiStatusType +} + +export const build_start = async (preset?: buildPresetType) => { + try { + const { data }: { data: buildStartResponseType } = await $v1.post("/bot/build/start", preset) + return data + } catch (error) { + console.log(error) + throw error + } +} + +export const build_stop = async (build_id: number) => { + try { + const { data } = await $v1.get(`/bot/build/stop/${build_id}`) + return data + } catch (error) { + console.log(error) + throw error + } +} + +export const build_status = async (build_id: number) => { + try { + const { data }: { data: buildStatusResponseType } = await $v1.get( + `/bot/build/status/${build_id}` + ) + return data + } catch (error) { + console.log(error) + throw error + } +} + +export const get_builds = async () => { + try { + const { data }: { data: buildMinifyApiType[] } = await $v1.get("/bot/builds") + // console.log(data) + return data + } catch (error) { + console.log(error) + throw error + } +} + +export const get_build = async (build_id: number) => { + try { + const { data }: { data: buildApiType } = await $v1.get(`/bot/builds/${build_id}`) + return data + } catch (error) { + console.log(error) + throw error + } +} + +export const get_runs = async () => { + try { + const { data }: { data: runMinifyApiType[] } = await $v1.get("/bot/runs") + // console.log(data) + return data + } catch (error) { + console.log(error) + throw error + } +} + +export const get_run = async (run_id: number) => { + try { + const { data }: { data: runApiType } = await $v1.get(`/bot/runs/${run_id}`) + return data + } catch (error) { + console.log(error) + throw error + } +} + +export const run_start = async (preset: buildPresetType, build_id: number) => { + try { + const { data }: runStartResponseType = await $v1.post(`/bot/run/start/${build_id}`, preset) + return data + } catch (error) { + console.log(error) + throw error + } +} + +export const run_stop = async (run_id: number) => { + try { + const { data }: { data: {status: 'ok' | 'error'} } = await $v1.get(`/bot/run/stop/${run_id}`) + return data + } catch (error) { + console.log(error) + throw error + } +} + +export const run_status = async (run_id: number) => { + try { + const { data }: { data: buildStatusResponseType } = await $v1.get(`/bot/run/status/${run_id}`) + return data + } catch (error) { + console.log(error) + throw error + } +} diff --git a/frontend/src/api/flows.ts b/frontend/src/api/flows.ts new file mode 100644 index 00000000..6b8b3ef0 --- /dev/null +++ b/frontend/src/api/flows.ts @@ -0,0 +1,13 @@ +import { $v1 } from "." +import { FlowType } from "../types/FlowTypes" +import { GetFlowsResponseType, SaveFlowsResponseType } from "./flows.types" + + + +export const get_flows = async (): Promise => { + return (await $v1.get("/flows")).data +} + +export const save_flows = async (flows: FlowType[]): Promise => { + return (await $v1.post("/flows", {flows})).data +} \ No newline at end of file diff --git a/frontend/src/api/flows.types.ts b/frontend/src/api/flows.types.ts new file mode 100644 index 00000000..6dab8ec4 --- /dev/null +++ b/frontend/src/api/flows.types.ts @@ -0,0 +1,13 @@ +import { FlowType } from "../types/FlowTypes" + + +export type GetFlowsResponseType = { + data: { + flows: FlowType[] + } + status: string +} + +export type SaveFlowsResponseType = { + status: string +} \ No newline at end of file diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts new file mode 100644 index 00000000..41a4cf83 --- /dev/null +++ b/frontend/src/api/index.ts @@ -0,0 +1,8 @@ +import axios from "axios"; +import { VITE_BASE_API_URL } from "../env.consts"; + +const baseURL = VITE_BASE_API_URL ?? "http://localhost:8000/api/v1" + +export const $v1 = axios.create({ + baseURL: baseURL +}) \ No newline at end of file diff --git a/frontend/src/assets/react.svg b/frontend/src/assets/react.svg new file mode 100644 index 00000000..6c87de9b --- /dev/null +++ b/frontend/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/components/chat/Chat.tsx b/frontend/src/components/chat/Chat.tsx new file mode 100644 index 00000000..73d67872 --- /dev/null +++ b/frontend/src/components/chat/Chat.tsx @@ -0,0 +1,277 @@ +import { Button, Textarea } from "@nextui-org/react" +import { a, useTransition } from "@react-spring/web" +import axios from "axios" +import { Paperclip, Send, Smile, X } from "lucide-react" +import { useContext, useEffect, useRef, useState } from "react" +import toast from "react-hot-toast" +import { useSearchParams } from "react-router-dom" +import { buildContext } from "../../contexts/buildContext" +import { chatContext } from "../../contexts/chatContext" +import { runContext } from "../../contexts/runContext" +import ChatIcon from "../../icons/buildmenu/ChatIcon" +import MonitorIcon from "../../icons/buildmenu/MonitorIcon" +import { parseSearchParams } from "../../utils" +import EmojiPicker, { EmojiType } from "./EmojiPicker" + +const Chat = () => { + const { logsPage, setLogsPage } = useContext(buildContext) + const { chat, setChat, messages, setMessages } = useContext(chatContext) + const { run, runStatus } = useContext(runContext) + const [searchParams, setSearchParams] = useSearchParams() + const ws = useRef(null) + + const [isEmoji, setIsEmoji] = useState(false) + + const [emojis, setEmojis] = useState([]) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [emojisPending, setEmojisPending] = useState(false) + useEffect(() => { + const getEmojis = async () => { + setEmojisPending(() => true) + const emojis_data = await axios + .get("https://emoji-api.com/emojis?access_key=4dd2f9e45b38e17c21b432caf8ac12206775bfef") + .finally(() => setEmojisPending(() => false)) + return emojis_data + } + + getEmojis() + .then(({ data }) => { + setEmojis(() => data) + }) + .catch(() => { + console.log("emojis load error") + }) + }, []) + + const [messageValue, setMessageValue] = useState("") + + const handleMessage = () => { + if (messageValue) { + if (ws.current && ws.current.readyState === 1) { + console.log(ws.current) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + ws.current.send(messageValue) + setMessages([ + ...messages, + { + message: messageValue, + type: "user", + }, + ]) + setMessageValue("") + setIsEmoji(false) + } else { + setMessages([ + ...messages, + { + message: "WS connection is not opened! Try to start any run!", + type: "system", + }, + ]) + setMessageValue("") + setIsEmoji(false) + } + } + } + + useEffect(() => { + const enterDownEvent = (e: KeyboardEvent) => { + if (e.key == "Enter") { + e.preventDefault() + handleMessage() + } + } + + document.addEventListener("keydown", enterDownEvent) + + return () => document.removeEventListener("keydown", enterDownEvent) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [messageValue, messages, setMessages]) + + const chatWindowRef = useRef(null) + + useEffect(() => { + chatWindowRef.current?.scrollBy({ + top: 999999, + behavior: "smooth", + }) + }, [messages.length]) + + const messagesT = useTransition(messages, { + from: { opacity: 0, y: 50 }, + enter: { opacity: 1, y: 0 }, + leave: { opacity: 0 }, + config: { + duration: 100, + }, + }) + + const emoji_transition = useTransition(isEmoji, { + from: { opacity: 0, transform: "scale(0.5)" }, + enter: { opacity: 1, transform: "scale(1)" }, + leave: { opacity: 0, transform: "scale(0.5)" }, + config: { + duration: 0, + }, + }) + + useEffect(() => { + if (runStatus === "alive" && run) { + const socket = new WebSocket(`ws://localhost:8000/api/v1/bot/run/connect?run_id=${run.id}`) + socket.onopen = (e) => { + console.log(e) + toast.success("Chat was successfully connected!") + } + socket.onmessage = (event: MessageEvent) => { + console.log(event) + if (event.data) { + // console.log(event.data) + const data = event.data.split(":")[2].split("attachments")[0].slice(0, -2) + // console.log(data) + setTimeout(() => { + setMessages((prev) => [...prev, { message: data, type: "bot" }]) + }, 500); + } + socket.onclose = (event) => { + socket.close() + console.log("websocket closed", event) + } + } + ws.current = socket + } + return () => { + ws.current?.close() + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [run, runStatus]) + + return ( +
+
+
+
+ + Chat +
+
+ + +
+
+
+ {messagesT((style, m) => ( + +
+ {m.message} +
+
+ ))} +
+
+ +
+
+ +
+ {emoji_transition((style, flag) => ( + <> + {chat && flag && ( + + { + setMessageValue((prev) => prev + emoji) + }} + lazy + theme='auto' + /> + + )} + + ))} +
+
+ +
+
+