From 26ebb17d47260f73e4e1f931ccf141f082f4f380 Mon Sep 17 00:00:00 2001 From: jaseemjaskp Date: Sun, 25 Feb 2024 16:19:36 +0530 Subject: [PATCH] Initial commit on Unstract --- .github/pull_request_template.md | 35 + .github/workflows/ci-container-build.yaml | 86 + .github/workflows/docker-build-push-dev.yaml | 64 + .../workflows/docker-tools-build-push.yaml | 65 + .github/workflows/production-build.yaml | 33 + .gitignore | 631 + .jshintrc | 3 + .pre-commit-config.yaml | 200 + CONTRIBUTE.md | 3 + README.md | 199 + backend/README.md | 136 + backend/account/ReadMe.md | 26 + backend/account/__init__.py | 0 backend/account/admin.py | 5 + backend/account/api_doc.md | 202 + backend/account/apps.py | 6 + backend/account/authentication_controller.py | 508 + backend/account/authentication_helper.py | 38 + .../account/authentication_plugin_registry.py | 98 + backend/account/authentication_service.py | 326 + backend/account/cache_service.py | 134 + backend/account/constants.py | 74 + backend/account/custom_auth_middleware.py | 144 + backend/account/custom_authentication.py | 13 + backend/account/custom_cache.py | 12 + backend/account/custom_exceptions.py | 66 + backend/account/dto.py | 130 + backend/account/enums.py | 6 + backend/account/exceptions.py | 26 + backend/account/migrations/0001_initial.py | 237 + .../migrations/0002_auto_20230718_1040.py | 39 + .../account/migrations/0003_platformkey.py | 65 + ...004_alter_platformkey_key_name_and_more.py | 23 + .../migrations/0005_encryptionsecret.py | 39 + backend/account/migrations/__init__.py | 0 backend/account/models.py | 141 + backend/account/organization.py | 42 + backend/account/serializer.py | 86 + backend/account/templates/index.html | 11 + backend/account/tests.py | 1 + backend/account/urls.py | 20 + backend/account/user.py | 50 + backend/account/views.py | 125 + backend/adapter_processor/__init__.py | 0 .../adapter_processor/adapter_processor.py | 280 + backend/adapter_processor/constants.py | 23 + backend/adapter_processor/exceptions.py | 55 + .../migrations/0001_initial.py | 109 + .../0002_adapterinstance_unique_adapter.py | 18 + ...0003_adapterinstance_adapter_metadata_b.py | 41 + ...0004_alter_adapterinstance_adapter_type.py | 26 + .../adapter_processor/migrations/__init__.py | 0 backend/adapter_processor/models.py | 78 + backend/adapter_processor/serializers.py | 91 + backend/adapter_processor/urls.py | 34 + backend/adapter_processor/views.py | 182 + backend/api/__init__.py | 0 backend/api/admin.py | 5 + backend/api/api_deployment_views.py | 113 + backend/api/api_key_views.py | 28 + backend/api/apps.py | 5 + backend/api/constants.py | 3 + backend/api/deployment_helper.py | 254 + backend/api/exceptions.py | 94 + backend/api/key_helper.py | 72 + backend/api/migrations/0001_initial.py | 185 + backend/api/migrations/__init__.py | 0 backend/api/models.py | 141 + backend/api/serializers.py | 124 + backend/api/tests.py | 1 + backend/api/urls.py | 52 + backend/apps/__init__.py | 0 backend/apps/constants.py | 4 + backend/apps/exceptions.py | 6 + backend/apps/urls.py | 9 + backend/apps/views.py | 22 + backend/backend/__init__.py | 3 + backend/backend/asgi.py | 20 + backend/backend/celery.py | 29 + backend/backend/constants.py | 30 + backend/backend/exceptions.py | 36 + backend/backend/flowerconfig.py | 15 + backend/backend/public_urls.py | 40 + backend/backend/serializers.py | 23 + backend/backend/settings/__init__.py | 0 backend/backend/settings/base.py | 458 + backend/backend/settings/dev.py | 27 + backend/backend/settings/test_cases.py | 3 + backend/backend/urls.py | 53 + backend/backend/wsgi.py | 25 + backend/connector/__init__.py | 0 backend/connector/admin.py | 5 + backend/connector/apps.py | 5 + .../connector/connector_instance_helper.py | 316 + backend/connector/constants.py | 17 + backend/connector/fields.py | 38 + backend/connector/migrations/0001_initial.py | 122 + ..._connectorinstance_connector_metadata_b.py | 42 + backend/connector/migrations/__init__.py | 0 backend/connector/models.py | 116 + backend/connector/serializers.py | 93 + backend/connector/tests/conftest.py | 9 + backend/connector/tests/connector_tests.py | 326 + .../tests/fixtures/fixtures_0001.json | 67 + backend/connector/unstract_account.py | 78 + backend/connector/urls.py | 16 + backend/connector/views.py | 128 + backend/connector_auth/__init__.py | 0 backend/connector_auth/admin.py | 5 + backend/connector_auth/apps.py | 6 + backend/connector_auth/constants.py | 18 + backend/connector_auth/exceptions.py | 31 + .../connector_auth/migrations/0001_initial.py | 54 + backend/connector_auth/migrations/__init__.py | 0 backend/connector_auth/models.py | 135 + backend/connector_auth/pipeline/common.py | 110 + backend/connector_auth/pipeline/google.py | 33 + backend/connector_auth/urls.py | 21 + backend/connector_auth/views.py | 45 + backend/connector_processor/__init__.py | 0 .../connector_processor.py | 167 + backend/connector_processor/constants.py | 27 + backend/connector_processor/exceptions.py | 50 + backend/connector_processor/serializers.py | 7 + backend/connector_processor/urls.py | 16 + backend/connector_processor/views.py | 84 + backend/cron_expression_generator/__init__.py | 0 .../cron_expression_generator/constants.py | 7 + .../cron_expression_generator/descriptor.py | 33 + .../cron_expression_generator/exceptions.py | 11 + .../cron_expression_generator/generator.py | 59 + .../cron_expression_generator/serializer.py | 12 + backend/cron_expression_generator/urls.py | 13 + backend/cron_expression_generator/views.py | 64 + backend/docs/__init__.py | 0 backend/docs/urls.py | 16 + backend/entrypoint.sh | 24 + backend/feature_flag/__init__.py | 0 backend/feature_flag/admin.py | 1 + backend/feature_flag/apps.py | 6 + backend/feature_flag/migrations/__init__.py | 0 backend/feature_flag/models.py | 1 + backend/feature_flag/urls.py | 12 + backend/feature_flag/views.py | 55 + backend/file_management/__init__.py | 0 backend/file_management/admin.py | 1 + backend/file_management/api_doc.md | 40 + backend/file_management/apps.py | 6 + backend/file_management/constants.py | 5 + backend/file_management/exceptions.py | 93 + .../file_management/file_management_dto.py | 37 + .../file_management/file_management_helper.py | 257 + .../file_management/migrations/__init__.py | 0 backend/file_management/models.py | 1 + backend/file_management/serializer.py | 33 + backend/file_management/tests.py | 1 + backend/file_management/urls.py | 64 + backend/file_management/views.py | 226 + backend/init.sql | 7 + backend/log_events/__init__.py | 0 backend/log_events/admin.py | 3 + backend/log_events/apps.py | 6 + backend/log_events/constants.py | 3 + backend/log_events/migrations/__init__.py | 0 backend/log_events/models.py | 3 + backend/log_events/tests.py | 3 + backend/log_events/urls.py | 3 + backend/log_events/views.py | 67 + backend/manage.py | 29 + backend/middleware/__init__.py | 0 backend/middleware/exception.py | 85 + backend/pdm.lock | 5004 +++ backend/permissions/__init__.py | 0 backend/permissions/permission.py | 14 + backend/pipeline/__init__.py | 0 backend/pipeline/constants.py | 65 + backend/pipeline/exceptions.py | 36 + backend/pipeline/manager.py | 82 + backend/pipeline/migrations/0001_initial.py | 132 + backend/pipeline/migrations/__init__.py | 0 backend/pipeline/models.py | 93 + backend/pipeline/pipeline_processor.py | 61 + backend/pipeline/serializers/crud.py | 114 + backend/pipeline/serializers/execute.py | 19 + backend/pipeline/static/etl_pipelines.json | 62 + backend/pipeline/static/task_pipelines.json | 47 + backend/pipeline/urls.py | 25 + backend/pipeline/views.py | 120 + backend/platform_settings/__init__.py | 0 backend/platform_settings/admin.py | 1 + backend/platform_settings/apps.py | 6 + backend/platform_settings/constants.py | 14 + backend/platform_settings/exceptions.py | 46 + .../platform_settings/migrations/__init__.py | 0 backend/platform_settings/models.py | 0 .../platform_settings/platform_auth_helper.py | 51 + .../platform_auth_service.py | 234 + backend/platform_settings/serializers.py | 25 + backend/platform_settings/tests.py | 1 + backend/platform_settings/urls.py | 26 + backend/platform_settings/views.py | 125 + backend/plugins/README.md | 5 + backend/plugins/__init__.py | 0 .../authentication/auth_sample/__init__.py | 8 + .../authentication/auth_sample/auth_helper.py | 36 + .../auth_sample/auth_service.py | 71 + .../plugins/authentication/auth_sample/dto.py | 41 + .../authentication/auth_sample/enums.py | 6 + .../authentication/auth_sample/exceptions.py | 6 + backend/project/__init__.py | 0 backend/project/admin.py | 5 + backend/project/apps.py | 5 + backend/project/constants.py | 8 + backend/project/exceptions.py | 6 + backend/project/migrations/0001_initial.py | 85 + backend/project/migrations/__init__.py | 0 backend/project/models.py | 59 + backend/project/serializers.py | 28 + backend/project/tests/conftest.py | 9 + .../project/tests/fixtures/fixtures_0001.json | 51 + backend/project/tests/project_tests.py | 122 + backend/project/urls.py | 27 + backend/project/views.py | 59 + backend/prompt/__init__.py | 0 backend/prompt/admin.py | 5 + backend/prompt/apps.py | 5 + backend/prompt/constants.py | 3 + backend/prompt/migrations/0001_initial.py | 73 + backend/prompt/migrations/__init__.py | 0 backend/prompt/models.py | 53 + backend/prompt/serializers.py | 19 + backend/prompt/tests/conftest.py | 10 + .../prompt/tests/fixtures/prompts_001.json | 81 + backend/prompt/tests/test_urls.py | 122 + backend/prompt/urls.py | 20 + backend/prompt/views.py | 46 + backend/prompt_studio/__init__.py | 0 .../prompt_profile_manager/__init__.py | 0 .../prompt_profile_manager/admin.py | 5 + .../prompt_profile_manager/apps.py | 5 + .../prompt_profile_manager/constants.py | 16 + .../prompt_profile_manager/exceptions.py | 6 + .../migrations/0001_initial.py | 109 + ...ove_profilemanager_vector_size_and_more.py | 47 + ...e_updated_at_profilemanager_modified_at.py | 17 + .../migrations/0003_merge_20240125_0530.py | 18 + ...ategy_profilemanager_retrieval_strategy.py | 17 + ..._converter_and_added_x2text_foreign_key.py | 65 + .../0006_alter_profilemanager_x2text.py | 27 + .../migrations/__init__.py | 0 .../prompt_profile_manager/models.py | 81 + .../prompt_profile_manager/serializers.py | 40 + .../prompt_profile_manager/urls.py | 32 + .../prompt_profile_manager/views.py | 59 + .../prompt_studio/prompt_studio/__init__.py | 0 backend/prompt_studio/prompt_studio/admin.py | 5 + backend/prompt_studio/prompt_studio/apps.py | 5 + .../prompt_studio/prompt_studio/constants.py | 28 + .../prompt_studio/prompt_studio/exceptions.py | 27 + .../prompt_studio/migrations/0001_initial.py | 145 + .../migrations/0002_prompt_eval_metrics.py | 48 + ...ve_toolstudioprompt_updated_at_and_more.py | 21 + .../0004_alter_toolstudioprompt_prompt.py | 19 + .../prompt_studio/migrations/__init__.py | 0 backend/prompt_studio/prompt_studio/models.py | 117 + .../prompt_studio/serializers.py | 15 + backend/prompt_studio/prompt_studio/urls.py | 31 + backend/prompt_studio/prompt_studio/views.py | 67 + .../prompt_studio_core/__init__.py | 0 .../prompt_studio/prompt_studio_core/admin.py | 5 + .../prompt_studio/prompt_studio_core/apps.py | 5 + .../prompt_studio_core/constants.py | 90 + .../prompt_studio_core/exceptions.py | 49 + .../migrations/0001_initial.py | 124 + .../0002_alter_customtool_output.py | 19 + ...mtool_updated_at_customtool_modified_at.py | 21 + .../migrations/0003_merge_20240125_1501.py | 15 + .../prompt_studio_core/migrations/__init__.py | 0 .../prompt_studio_core/models.py | 66 + .../prompt_ide_base_tool.py | 44 + .../prompt_studio_helper.py | 403 + .../prompt_studio_core/serializers.py | 48 + .../static/select_choices.json | 34 + .../prompt_studio/prompt_studio_core/urls.py | 59 + .../prompt_studio/prompt_studio_core/views.py | 183 + .../prompt_studio_output_manager/__init__.py | 0 .../prompt_studio_output_manager/admin.py | 5 + .../prompt_studio_output_manager/apps.py | 5 + .../prompt_studio_output_manager/constants.py | 5 + .../exceptions.py | 7 + .../migrations/0001_initial.py | 95 + ...0002_promptstudiooutputmanager_doc_name.py | 22 + ...lter_promptstudiooutputmanager_doc_name.py | 23 + ...lter_promptstudiooutputmanager_doc_name.py | 20 + ...ooutputmanager_profile_manager_and_more.py | 52 + ..._alter_promptstudiooutputmanager_output.py | 22 + .../migrations/__init__.py | 0 .../prompt_studio_output_manager/models.py | 67 + .../serializers.py | 10 + .../prompt_studio_output_manager/urls.py | 17 + .../prompt_studio_output_manager/views.py | 37 + .../prompt_studio_registry/__init__.py | 0 .../prompt_studio_registry/admin.py | 5 + .../prompt_studio_registry/apps.py | 5 + .../prompt_studio_registry/constants.py | 105 + .../prompt_studio_registry/exceptions.py | 32 + .../prompt_studio_registry/fields.py | 29 + .../migrations/0001_initial.py | 87 + ...romptstudioregistry_updated_at_and_more.py | 21 + ...ptstudioregistry_tool_metadata_and_more.py | 43 + .../0004_promptstudioregistry_custom_tool.py | 28 + .../0005_delete_corrupt_tool_instance.py | 30 + .../migrations/__init__.py | 0 .../prompt_studio_registry/models.py | 74 + .../prompt_studio_registry_helper.py | 258 + .../prompt_studio_registry/serializers.py | 14 + .../static/select_choices.json | 31 + .../prompt_studio_registry/urls.py | 15 + .../prompt_studio_registry/views.py | 71 + backend/pyproject.toml | 88 + backend/sample.env | 102 + backend/scheduler/__init__.py | 0 backend/scheduler/admin.py | 1 + backend/scheduler/apps.py | 14 + backend/scheduler/constants.py | 12 + backend/scheduler/exceptions.py | 11 + backend/scheduler/helper.py | 53 + backend/scheduler/serializer.py | 50 + backend/scheduler/settings.py | 0 backend/scheduler/tasks.py | 122 + backend/scheduler/views.py | 86 + backend/tenant_account/__init__.py | 0 backend/tenant_account/admin.py | 1 + backend/tenant_account/apps.py | 6 + backend/tenant_account/constants.py | 14 + backend/tenant_account/dto.py | 15 + backend/tenant_account/enums.py | 6 + backend/tenant_account/invitation_urls.py | 20 + backend/tenant_account/invitation_views.py | 44 + .../tenant_account/migrations/0001_initial.py | 42 + .../0002_organizationmember_delete_user.py | 45 + ...ter_organizationmember_options_and_more.py | 55 + ...0004_alter_organizationmember_member_id.py | 17 + backend/tenant_account/migrations/__init__.py | 0 backend/tenant_account/models.py | 16 + .../organization_member_service.py | 26 + backend/tenant_account/serializer.py | 161 + backend/tenant_account/templates/land.html | 11 + backend/tenant_account/tests.py | 1 + backend/tenant_account/urls.py | 11 + backend/tenant_account/users_urls.py | 36 + backend/tenant_account/users_view.py | 172 + backend/tenant_account/views.py | 87 + backend/tool_instance/__init__.py | 0 backend/tool_instance/admin.py | 5 + backend/tool_instance/apps.py | 5 + backend/tool_instance/constants.py | 45 + backend/tool_instance/exceptions.py | 41 + .../tool_instance/migrations/0001_initial.py | 136 + backend/tool_instance/migrations/__init__.py | 0 backend/tool_instance/models.py | 100 + backend/tool_instance/serializers.py | 130 + backend/tool_instance/tests.py | 1 + backend/tool_instance/tool_instance_helper.py | 324 + backend/tool_instance/tool_processor.py | 140 + backend/tool_instance/urls.py | 46 + backend/tool_instance/views.py | 172 + backend/utils/__init__.py | 0 backend/utils/common_utils.py | 23 + backend/utils/constants.py | 9 + backend/utils/filtering.py | 21 + backend/utils/models/base_model.py | 9 + backend/utils/request/__init__.py | 3 + backend/utils/request/constants.py | 8 + backend/utils/request/feature_flag.py | 40 + backend/utils/request/request.py | 49 + backend/utils/seed_data/README.md | 27 + backend/utils/seed_data/seed_data.py | 61 + backend/utils/serializer_utils.py | 31 + backend/workflow_manager/__init__.py | 0 backend/workflow_manager/endpoint/__init__.py | 0 backend/workflow_manager/endpoint/admin.py | 1 + backend/workflow_manager/endpoint/apps.py | 6 + .../endpoint/base_connector.py | 96 + .../workflow_manager/endpoint/constants.py | 85 + .../endpoint/database_utils.py | 268 + .../workflow_manager/endpoint/destination.py | 430 + .../endpoint/endpoint_utils.py | 30 + .../workflow_manager/endpoint/exceptions.py | 63 + .../endpoint/migrations/0001_initial.py | 88 + .../endpoint/migrations/__init__.py | 0 backend/workflow_manager/endpoint/models.py | 51 + .../workflow_manager/endpoint/serializers.py | 12 + backend/workflow_manager/endpoint/source.py | 482 + .../endpoint/static/dest/db.json | 55 + .../endpoint/static/dest/file.json | 25 + .../endpoint/static/src/api.json | 23 + .../endpoint/static/src/file.json | 41 + backend/workflow_manager/endpoint/tests.py | 1 + backend/workflow_manager/endpoint/urls.py | 25 + backend/workflow_manager/endpoint/views.py | 86 + backend/workflow_manager/urls.py | 20 + backend/workflow_manager/workflow/__init__.py | 0 backend/workflow_manager/workflow/admin.py | 4 + backend/workflow_manager/workflow/apps.py | 6 + .../workflow_manager/workflow/constants.py | 60 + backend/workflow_manager/workflow/dto.py | 68 + backend/workflow_manager/workflow/enums.py | 73 + .../workflow_manager/workflow/exceptions.py | 67 + .../workflow_manager/workflow/execution.py | 455 + .../workflow/file_history_helper.py | 70 + .../workflow_manager/workflow/generator.py | 118 + .../workflow/migrations/0001_initial.py | 287 + .../workflow/migrations/__init__.py | 0 .../workflow/models/__init__.py | 3 + .../workflow/models/execution.py | 64 + .../workflow/models/file_history.py | 42 + .../workflow/models/workflow.py | 84 + .../workflow_manager/workflow/serializers.py | 149 + backend/workflow_manager/workflow/tests.py | 1 + backend/workflow_manager/workflow/urls.py | 76 + backend/workflow_manager/workflow/views.py | 372 + .../workflow/workflow_helper.py | 728 + docker/README.md | 63 + docker/docker-compose-dev-essentials.yaml | 121 + docker/docker-compose.build.yaml | 38 + docker/docker-compose.yaml | 165 + docker/dockerfiles/backend.Dockerfile | 59 + .../backend.Dockerfile.dockerignore | 40 + docker/dockerfiles/document.Dockerfile | 58 + .../document.Dockerfile.dockerignore | 40 + docker/dockerfiles/frontend.Dockerfile | 33 + .../frontend.Dockerfile.dockerignore | 12 + docker/dockerfiles/platform.Dockerfile | 56 + .../platform.Dockerfile.dockerignore | 8 + docker/dockerfiles/prompt.Dockerfile | 82 + .../prompt.Dockerfile.dockerignore | 8 + docker/dockerfiles/worker.Dockerfile | 46 + .../worker.Dockerfile.dockerignore | 42 + docker/dockerfiles/x2text.Dockerfile | 43 + .../x2text.Dockerfile.dockerignore | 8 + docker/sample.essentials.env | 15 + docker/sample.proxy_overrides.yaml | 22 + docker/scripts/check_container_exited.sh | 7 + docker/scripts/deploy.sh | 145 + .../resolve_container_svc_from_host.sh | 110 + document-service/.gitignore | 162 + document-service/README.md | 72 + document-service/pdm.lock | 335 + document-service/pyproject.toml | 34 + document-service/sample.env | 12 + .../src/unstract/document_service/__init__.py | 0 .../src/unstract/document_service/main.py | 218 + document-service/tests/__init__.py | 0 .../thunder-collection_document-service.json | 97 + document-service/wrapper.sh | 15 + frontend/.eslintrc.json | 69 + frontend/.gitignore | 24 + frontend/README.md | 127 + frontend/nginx.conf | 53 + frontend/package-lock.json | 34979 ++++++++++++++++ frontend/package.json | 77 + frontend/public/favicon.ico | Bin 0 -> 6044 bytes frontend/public/index.html | 19 + frontend/public/manifest.json | 15 + frontend/sample.env | 1 + frontend/src/App.jsx | 42 + frontend/src/assets/BingAds.svg | 9 + frontend/src/assets/Unstract.svg | 21 + frontend/src/assets/UnstractLogoBlack.svg | 21 + frontend/src/assets/Workflows.svg | 3 + frontend/src/assets/api-deployments.svg | 10 + frontend/src/assets/appdev.svg | 3 + frontend/src/assets/assertion.svg | 3 + frontend/src/assets/bg_shape.svg | 18 + frontend/src/assets/combined-output.svg | 12 + frontend/src/assets/connect_embedding.svg | 22 + frontend/src/assets/connect_llm.svg | 35 + frontend/src/assets/connect_vector_db.svg | 50 + frontend/src/assets/custom-tools-icon.svg | 3 + frontend/src/assets/document.svg | 3 + frontend/src/assets/embedding.svg | 3 + frontend/src/assets/empty.svg | 9 + frontend/src/assets/etl.svg | 3 + frontend/src/assets/folder.svg | 3 + frontend/src/assets/index.js | 43 + frontend/src/assets/input-placeholder.svg | 12 + frontend/src/assets/landing_bg.png | Bin 0 -> 12629 bytes frontend/src/assets/landing_bg.svg | 9 + .../src/assets/list-of-tools-placeholder.svg | 13 + .../assets/list-of-wf-steps-placeholder.svg | 29 + frontend/src/assets/llm.svg | 3 + frontend/src/assets/login-page-bg.svg | 49 + frontend/src/assets/loginPageSS.webp | Bin 0 -> 49114 bytes frontend/src/assets/logo-24.svg | 6 + frontend/src/assets/logo-64.svg | 6 + frontend/src/assets/moon-icon.svg | 1 + frontend/src/assets/output-placeholder.svg | 12 + frontend/src/assets/platform-settings.svg | 3 + frontend/src/assets/steps.svg | 1 + frontend/src/assets/sun-icon.svg | 2 + frontend/src/assets/swatch.svg | 9 + frontend/src/assets/task.svg | 3 + .../tool-ide-input-document-placeholder.svg | 20 + .../assets/tool-ide-prompts-placeholder.svg | 25 + frontend/src/assets/tool.svg | 12 + frontend/src/assets/vector-db.svg | 3 + .../src/components/agency/actions/Actions.css | 21 + .../src/components/agency/actions/Actions.jsx | 428 + .../src/components/agency/agency/Agency.css | 59 + .../src/components/agency/agency/Agency.jsx | 260 + .../components/agency/cards-list/CardList.css | 30 + .../agency/cards-list/CardsList.jsx | 195 + .../ConfigurationModal.css | 0 .../ConfigurationModal.jsx | 25 + .../agency/configuration/Configuration.css | 10 + .../agency/configuration/Configuration.jsx | 135 + .../ConfigureConnectorModal.css | 95 + .../ConfigureConnectorModal.jsx | 117 + .../ConfigureFormsLayout.jsx | 83 + .../ds-settings-card/DsSettingsCard.jsx | 336 + .../agency/file-upload/FileUpload.jsx | 65 + .../agency/input-output/InputOutput.css | 33 + .../agency/input-output/InputOutput.jsx | 54 + .../list-of-connectors/ListOfConnectors.jsx | 25 + .../agency/list-of-tools/ListOfTools.css | 5 + .../agency/list-of-tools/ListOfTools.jsx | 35 + .../agency/logs-label/LogsLabel.css | 3 + .../agency/logs-label/LogsLabel.jsx | 43 + .../markdown-renderer/MarkdownRenderer.css | 1 + .../markdown-renderer/MarkdownRenderer.jsx | 32 + .../src/components/agency/prompt/Prompt.css | 15 + .../src/components/agency/prompt/Prompt.jsx | 135 + .../agency/settings-form/SettingsForm.jsx | 42 + .../agency/side-panel/SidePanel.css | 14 + .../agency/side-panel/SidePanel.jsx | 93 + .../components/agency/step-card/StepCard.css | 48 + .../components/agency/step-card/StepCard.jsx | 65 + .../src/components/agency/steps/Steps.css | 65 + .../src/components/agency/steps/Steps.jsx | 201 + .../components/agency/tool-icon/ToolIcon.css | 7 + .../components/agency/tool-icon/ToolIcon.jsx | 29 + .../agency/tool-info-card/ToolInfoCard.css | 31 + .../agency/tool-info-card/ToolInfoCard.jsx | 51 + .../agency/tool-settings/ToolSettings.css | 9 + .../agency/tool-settings/ToolSettings.jsx | 105 + .../src/components/agency/tools/Tools.css | 13 + .../src/components/agency/tools/Tools.jsx | 81 + .../WorkflowExecutionMain.css | 28 + .../WorkflowExecutionMain.jsx | 57 + .../workflow-execution/WorkflowExecution.css | 21 + .../workflow-execution/WorkflowExecution.jsx | 48 + .../workflow-execution/workflow_actions.js | 8 + .../AddCustomToolFormModal.css | 10 + .../AddCustomToolFormModal.jsx | 171 + .../AddLlmProfileModal.css | 5 + .../AddLlmProfileModal.jsx | 416 + .../combined-output/CombinedOutput.css | 39 + .../combined-output/CombinedOutput.jsx | 141 + .../CustomSynonymsModal.css | 1 + .../CustomSynonymsModal.jsx | 26 + .../custom-synonyms/CustomSynonyms.css | 10 + .../custom-synonyms/CustomSynonyms.jsx | 218 + .../custom-tools/display-logs/DisplayLogs.css | 15 + .../custom-tools/display-logs/DisplayLogs.jsx | 78 + .../document-manager/DocumentManager.css | 40 + .../document-manager/DocumentManager.jsx | 105 + .../document-parser/DocumentParser.css | 13 + .../document-parser/DocumentParser.jsx | 216 + .../edit-tool-info/EditToolInfo.css | 9 + .../edit-tool-info/EditToolInfo.jsx | 56 + .../editable-text/EditableText.css | 17 + .../editable-text/EditableText.jsx | 110 + .../eval-metric-tag/EvalMetricTag.css | 68 + .../eval-metric-tag/EvalMetricTag.jsx | 68 + .../custom-tools/eval-modal/EvalModal.jsx | 155 + .../footer-layout/FooterLayout.css | 5 + .../footer-layout/FooterLayout.jsx | 17 + .../components/custom-tools/footer/Footer.css | 7 + .../components/custom-tools/footer/Footer.jsx | 45 + .../generate-index/GenerateIndex.css | 21 + .../generate-index/GenerateIndex.jsx | 80 + .../components/custom-tools/header/Header.css | 31 + .../components/custom-tools/header/Header.jsx | 157 + .../list-of-tools/ListOfTools.css | 45 + .../list-of-tools/ListOfTools.jsx | 233 + .../manage-docs-modal/ManageDocsModal.css | 20 + .../manage-docs-modal/ManageDocsModal.jsx | 232 + .../ManageLlmProfilesModal.jsx | 37 + .../manage-llm-profiles/ManageLlmProfiles.css | 5 + .../manage-llm-profiles/ManageLlmProfiles.jsx | 207 + .../custom-tools/notes-card/NotesCard.css | 15 + .../custom-tools/notes-card/NotesCard.jsx | 75 + .../OutputForDocModal.css | 18 + .../OutputForDocModal.jsx | 134 + .../custom-tools/pdf-viewer/PdfViewer.jsx | 102 + .../PreAndPostAmbleModal.css | 23 + .../PreAndPostAmbleModal.jsx | 120 + .../custom-tools/prompt-card/PromptCard.css | 111 + .../custom-tools/prompt-card/PromptCard.jsx | 839 + .../custom-tools/tool-ide/ToolIde.css | 103 + .../custom-tools/tool-ide/ToolIde.jsx | 261 + .../custom-tools/tools-main/ToolsMain.css | 26 + .../custom-tools/tools-main/ToolsMain.jsx | 151 + .../custom-tools/view-tools/ViewTools.css | 1 + .../custom-tools/view-tools/ViewTools.jsx | 59 + .../api-deployment/ApiDeployment.jsx | 354 + .../api-deployment/api-deployments-service.js | 87 + .../src/components/deployments/body/Body.jsx | 85 + .../CreateApiDeploymentModal.jsx | 250 + .../deployments/delete-modal/DeleteModal.jsx | 24 + .../deployments/display-code/CodeSnippet.css | 5 + .../deployments/display-code/CodeSnippet.jsx | 23 + .../deployments/display-code/DisplayCode.css | 15 + .../deployments/display-code/DisplayCode.jsx | 193 + .../components/deployments/header/Header.jsx | 34 + .../components/deployments/layout/Layout.css | 66 + .../components/deployments/layout/Layout.jsx | 34 + .../deployments/manage-keys/ManageKeys.css | 17 + .../deployments/manage-keys/ManageKeys.jsx | 364 + .../error/GenericError/GenericError.jsx | 59 + .../components/error/NotFound/NotFound.css | 1 + .../components/error/NotFound/NotFound.jsx | 20 + .../error/UnAuthorized/Unauthorized.css | 9 + .../error/UnAuthorized/Unauthorized.jsx | 19 + .../helpers/auth/PersistentLogin.js | 39 + .../components/helpers/auth/RequireAdmin.js | 23 + .../components/helpers/auth/RequireAuth.js | 25 + .../components/helpers/auth/RequireGuest.js | 18 + .../helpers/custom-tools/CustomToolsHelper.js | 105 + .../helpers/project/ProjectHelper.js | 75 + .../helpers/socket-messages/SocketMessages.js | 66 + .../add-source-modal/AddSourceModa.css | 1 + .../add-source-modal/AddSourceModal.jsx | 124 + .../input-output/add-source/AddSource.css | 1 + .../input-output/add-source/AddSource.jsx | 117 + .../input-output/configure-ds/ConfigureDs.css | 23 + .../input-output/configure-ds/ConfigureDs.jsx | 284 + .../data-source-card/DataSourceCard.css | 27 + .../data-source-card/DataSourceCard.jsx | 38 + .../edit-ds-modal/EditDsModal.css | 11 + .../edit-ds-modal/EditDsModal.jsx | 117 + .../input-output/file-system/FileSystem.css | 52 + .../input-output/file-system/FileSystem.jsx | 195 + .../input-output/input-output/InputOutput.css | 14 + .../input-output/input-output/InputOutput.jsx | 171 + .../input-output/input-service.js | 26 + .../list-of-sources/ListOfSources.css | 15 + .../list-of-sources/ListOfSources.jsx | 114 + .../input-output/manage-files/ManageFiles.css | 0 .../input-output/manage-files/ManageFiles.jsx | 46 + .../input-output/sidebar/Sidebar.css | 16 + .../input-output/sidebar/Sidebar.jsx | 46 + frontend/src/components/log-in/Login.css | 80 + frontend/src/components/log-in/Login.jsx | 61 + .../navigations/side-nav-bar/SideNavBar.css | 106 + .../navigations/side-nav-bar/SideNavBar.jsx | 217 + .../navigations/top-nav-bar/TopNavBar.css | 43 + .../navigations/top-nav-bar/TopNavBar.jsx | 148 + .../oauth-ds/google/GoogleOAuthButton.css | 5 + .../oauth-ds/google/GoogleOAuthButton.jsx | 32 + .../components/oauth-ds/oauth-ds/OAuthDs.jsx | 81 + .../oauth-ds/oauth-status/OAuthStatus.css | 11 + .../oauth-ds/oauth-status/OAuthStatus.jsx | 34 + frontend/src/components/onboard/OnBoard.jsx | 141 + frontend/src/components/onboard/onBoard.css | 102 + .../app-deploy/AppDeploy.jsx | 92 + .../delete-modal/DeleteModal.jsx | 24 + .../etl-task-deploy/EtlTaskDeploy.css | 1 + .../etl-task-deploy/EtlTaskDeploy.jsx | 387 + .../header/Header.css | 22 + .../header/Header.jsx | 54 + .../PipelinesOrDeployments.css | 56 + .../PipelinesOrDeployments.jsx | 276 + .../pipelines/Pipelines.css | 6 + .../pipelines/Pipelines.jsx | 496 + frontend/src/components/profile/Profile.css | 19 + frontend/src/components/profile/Profile.jsx | 41 + .../AltDateTimeWidget.jsx | 42 + .../alt-date-widget/AltDateWidget.jsx | 31 + .../array-field/ArrayField.css | 15 + .../array-field/ArrayField.jsx | 70 + .../checkbox-widget/CheckboxWidget.css | 8 + .../checkbox-widget/CheckboxWidget.jsx | 33 + .../checkboxes-widget/CheckboxesWidget.jsx | 41 + .../color-widget/ColorWidget.jsx | 25 + .../date-time-widget/DateTimeWidget.jsx | 32 + .../date-widget/DateWidget.jsx | 31 + .../email-widget/EmailWidget.jsx | 26 + .../file-widget/FileWidget.jsx | 31 + .../hidden-widget/HiddenWidget.jsx | 19 + .../password-widget/PasswordWidget.jsx | 32 + .../select-widget/SelectWidget.jsx | 37 + .../text-widget/TextWidget.jsx | 33 + .../time-widget/TimeWidget.jsx | 31 + .../up-down-widget/UpDownWidget.jsx | 26 + .../url-widget/URLWidget.jsx | 28 + .../settings/default-triad/DefaultTriad.css | 6 + .../settings/default-triad/DefaultTriad.jsx | 197 + .../settings/invite/InviteEditUser.css | 34 + .../settings/invite/InviteEditUser.jsx | 195 + .../settings/platform/PlatformSettings.css | 33 + .../settings/platform/PlatformSettings.jsx | 316 + .../components/settings/settings/Settings.css | 23 + .../components/settings/settings/Settings.jsx | 54 + .../src/components/settings/users/Users.css | 17 + .../src/components/settings/users/Users.jsx | 235 + .../list-of-items/ListOfItems.css | 14 + .../list-of-items/ListOfItems.jsx | 93 + .../tool-settings/ToolSettings.css | 29 + .../tool-settings/ToolSettings.jsx | 158 + .../widgets/confirm-modal/ConfirmModal.jsx | 42 + .../widgets/custom-button/CustomButton.css | 13 + .../widgets/custom-button/CustomButton.jsx | 22 + .../widgets/empty-state/EmptyState.jsx | 34 + .../widgets/error-boundary/ErrorBoundary.jsx | 47 + .../components/widgets/grid-view/GridView.css | 21 + .../components/widgets/grid-view/GridView.jsx | 100 + .../widgets/lazy-loader/LazyLoader.jsx | 30 + .../components/widgets/list-view/ListView.css | 13 + .../components/widgets/list-view/ListView.jsx | 69 + .../widgets/space-wrapper/SpaceWrapper.jsx | 16 + .../widgets/spinner-loader/SpinnerLoader.css | 23 + .../widgets/spinner-loader/SpinnerLoader.jsx | 38 + .../src/components/widgets/top-bar/TopBar.css | 21 + .../src/components/widgets/top-bar/TopBar.jsx | 59 + .../workflows/new-workflow/NewWorkflow.jsx | 96 + .../workflows/workflow/Workflows.css | 84 + .../workflows/workflow/Workflows.jsx | 481 + .../workflows/workflow/workflow-service.js | 84 + frontend/src/helpers/GetSessionData.js | 25 + frontend/src/helpers/GetStaticData.js | 290 + frontend/src/helpers/SocketContext.js | 41 + frontend/src/hooks/useAxiosPrivate.js | 31 + frontend/src/hooks/useLogout.js | 16 + frontend/src/hooks/useSessionValid.js | 83 + frontend/src/index.css | 111 + frontend/src/index.js | 25 + .../ContentCenterLayout.css | 31 + .../ContentCenterLayout.jsx | 40 + .../fullpage-payout/FullPageLayout.css | 8 + .../fullpage-payout/FullPageLayout.jsx | 13 + .../layouts/island-layout/IslandLayout.css | 11 + .../layouts/island-layout/IslandLayout.jsx | 17 + .../src/layouts/menu-layout/MenuLayout.css | 54 + .../src/layouts/menu-layout/MenuLayout.jsx | 88 + .../src/layouts/page-layout/PageLayout.css | 24 + .../src/layouts/page-layout/PageLayout.jsx | 38 + .../rjsf-form-layout/RjsfFormLayout.css | 21 + .../rjsf-form-layout/RjsfFormLayout.jsx | 139 + .../rjsf-widget-layout/RjsfWidgetLayout.css | 15 + .../rjsf-widget-layout/RjsfWidgetLayout.jsx | 30 + frontend/src/pages/AgencyPage.jsx | 7 + frontend/src/pages/AppDevelopmentPage.jsx | 5 + frontend/src/pages/CustomTools.jsx | 7 + frontend/src/pages/DeploymentsPage.jsx | 18 + frontend/src/pages/InputOutputPage.jsx | 7 + frontend/src/pages/InviteEditUserPage.jsx | 7 + frontend/src/pages/LandingPage.jsx | 7 + frontend/src/pages/OnBoardPage.jsx | 7 + .../src/pages/PipelinesOrDeploymentsPage.jsx | 12 + frontend/src/pages/ProfilePage.jsx | 7 + frontend/src/pages/SettingsPage.jsx | 7 + frontend/src/pages/ToolIdePage.jsx | 7 + frontend/src/pages/ToolsSettingsPage.jsx | 13 + frontend/src/pages/UsersPage.jsx | 7 + frontend/src/pages/WorkflowsPage.jsx | 7 + frontend/src/routes/Router.jsx | 105 + frontend/src/setupProxy.js | 11 + frontend/src/setupTests.js | 5 + frontend/src/store/alert-store.js | 18 + frontend/src/store/custom-tool-store.js | 77 + frontend/src/store/session-store.js | 20 + frontend/src/store/socket-logs-store.js | 45 + frontend/src/store/socket-messages-store.js | 40 + frontend/src/store/tool-settings.js | 28 + frontend/src/store/workflow-store.js | 81 + frontend/src/variables.css | 43 + pdm.lock | 5193 +++ platform-service/.gitignore | 162 + platform-service/README.md | 44 + platform-service/pdm.lock | 455 + platform-service/pyproject.toml | 40 + platform-service/sample.env | 25 + .../src/unstract/platform_service/__init__.py | 0 .../unstract/platform_service/exceptions.py | 7 + .../src/unstract/platform_service/helper.py | 71 + .../src/unstract/platform_service/main.py | 479 + .../tests/test_auth_middleware.py | 19 + prompt-service/.gitignore | 164 + prompt-service/README.md | 1 + prompt-service/pdm.lock | 3945 ++ prompt-service/pyproject.toml | 39 + prompt-service/sample.env | 11 + .../src/unstract/prompt_service/__init__.py | 0 .../authentication_middleware.py | 82 + .../src/unstract/prompt_service/constants.py | 109 + .../src/unstract/prompt_service/helper.py | 79 + .../src/unstract/prompt_service/main.py | 931 + .../prompt_service/prompt_ide_base_tool.py | 44 + pyproject.toml | 108 + tools/README.md | 309 + tools/classifier/.dockerignore | 3 + tools/classifier/Dockerfile | 21 + tools/classifier/README.md | 120 + tools/classifier/__init__.py | 0 tools/classifier/requirements.txt | 6 + tools/classifier/sample.env | 11 + tools/classifier/src/config/icon.svg | 53 + tools/classifier/src/config/properties.json | 62 + .../src/config/runtime_variables.json | 40 + tools/classifier/src/config/spec.json | 26 + tools/classifier/src/helper.py | 29 + tools/classifier/src/main.py | 196 + tools/doc_pii_redactor/.dockerignore | 3 + tools/doc_pii_redactor/Dockerfile | 20 + tools/doc_pii_redactor/README.md | 140 + tools/doc_pii_redactor/__init__.py | 0 tools/doc_pii_redactor/requirements.txt | 8 + tools/doc_pii_redactor/sample.env | 13 + tools/doc_pii_redactor/src/config/icon.svg | 53 + .../src/config/properties.json | 45 + .../src/config/runtime_variables.json | 40 + tools/doc_pii_redactor/src/config/spec.json | 72 + .../src/doc_pii_redactor/__init__.py | 0 .../src/doc_pii_redactor/constants.py | 7 + .../src/doc_pii_redactor/enums.py | 6 + .../src/doc_pii_redactor/helper.py | 157 + tools/doc_pii_redactor/src/main.py | 200 + tools/indexer/.dockerignore | 3 + tools/indexer/Dockerfile | 25 + tools/indexer/README.md | 127 + tools/indexer/__init__.py | 0 tools/indexer/requirements.txt | 4 + tools/indexer/sample.env | 7 + tools/indexer/src/config/icon.svg | 49 + tools/indexer/src/config/properties.json | 79 + .../indexer/src/config/runtime_variables.json | 7 + tools/indexer/src/config/spec.json | 26 + tools/indexer/src/constants.py | 5 + tools/indexer/src/main.py | 78 + tools/structure/.dockerignore | 3 + tools/structure/Dockerfile | 25 + tools/structure/README.md | 121 + tools/structure/__init__.py | 0 tools/structure/requirements.txt | 4 + tools/structure/sample.env | 13 + tools/structure/src/config/icon.svg | 53 + tools/structure/src/config/properties.json | 46 + .../src/config/runtime_variables.json | 5 + tools/structure/src/config/spec.json | 9 + tools/structure/src/constants.py | 51 + tools/structure/src/main.py | 120 + tools/text_extractor/.dockerignore | 3 + tools/text_extractor/.gitignore | 162 + tools/text_extractor/Dockerfile | 21 + tools/text_extractor/README.md | 117 + tools/text_extractor/__init__.py | 0 tools/text_extractor/requirements.txt | 4 + tools/text_extractor/sample.env | 8 + tools/text_extractor/src/config/icon.svg | 53 + .../text_extractor/src/config/properties.json | 53 + .../src/config/runtime_variables.json | 18 + tools/text_extractor/src/config/spec.json | 7 + .../src/example_package/__init__.py | 0 tools/text_extractor/src/main.py | 110 + tools/text_extractor/tests/__init__.py | 0 tools/translate/.dockerignore | 3 + tools/translate/Dockerfile | 19 + tools/translate/README.md | 132 + tools/translate/__init__.py | 0 tools/translate/requirements.txt | 6 + tools/translate/sample.env | 4 + tools/translate/src/config/icon.svg | 21 + tools/translate/src/config/properties.json | 41 + .../src/config/runtime_variables.json | 15 + tools/translate/src/config/spec.json | 82 + tools/translate/src/constants.py | 72 + tools/translate/src/main.py | 159 + unstract/connectors/README.md | 48 + unstract/connectors/pyproject.toml | 41 + .../src/unstract/connectors/__init__.py | 7 + .../src/unstract/connectors/base.py | 74 + .../src/unstract/connectors/connectorkit.py | 120 + .../src/unstract/connectors/constants.py | 4 + .../unstract/connectors/databases/__init__.py | 5 + .../connectors/databases/bigquery/__init__.py | 9 + .../connectors/databases/bigquery/bigquery.py | 53 + .../bigquery/static/json_schema.json | 22 + .../connectors/databases/mariadb/__init__.py | 9 + .../connectors/databases/mariadb/mariadb.py | 60 + .../databases/mariadb/static/json_schema.json | 46 + .../connectors/databases/mssql/__init__.py | 9 + .../connectors/databases/mssql/mssql.py | 64 + .../databases/mssql/static/json_schema.json | 46 + .../connectors/databases/mysql/__init__.py | 9 + .../connectors/databases/mysql/mysql.py | 58 + .../databases/mysql/static/json_schema.json | 46 + .../databases/postgresql/__init__.py | 9 + .../databases/postgresql/postgresql.py | 75 + .../postgresql/static/json_schema.json | 60 + .../connectors/databases/redshift/__init__.py | 9 + .../connectors/databases/redshift/redshift.py | 63 + .../redshift/static/json_schema.json | 51 + .../unstract/connectors/databases/register.py | 39 + .../databases/snowflake/__init__.py | 9 + .../databases/snowflake/snowflake.py | 65 + .../snowflake/static/json_schema.json | 58 + .../connectors/databases/unstract_db.py | 71 + .../src/unstract/connectors/enums.py | 8 + .../src/unstract/connectors/exceptions.py | 33 + .../connectors/filesystems/__init__.py | 5 + .../filesystems/account_services/__init__.py | 0 .../question_answering/apple_10K_2022.pdf | Bin 0 -> 729516 bytes .../connectors/filesystems/box/__init__.py | 11 + .../connectors/filesystems/box/box.py | 118 + .../filesystems/box/static/json_schema.json | 22 + .../filesystems/google_drive/__init__.py | 11 + .../filesystems/google_drive/constants.py | 3 + .../filesystems/google_drive/google_drive.py | 96 + .../google_drive/static/json_schema.json | 15 + .../google_drive/static/settings.yaml | 1 + .../connectors/filesystems/http/__init__.py | 11 + .../connectors/filesystems/http/http.py | 77 + .../filesystems/http/static/json_schema.json | 32 + .../local_storage/local_storage.py | 70 + .../local_storage/static/json_schema.json | 22 + .../connectors/filesystems/minio/__init__.py | 11 + .../connectors/filesystems/minio/minio.py | 87 + .../filesystems/minio/static/json_schema.json | 53 + .../connectors/filesystems/register.py | 38 + .../connectors/filesystems/ucs/__init__.py | 11 + .../connectors/filesystems/ucs/constants.py | 6 + .../filesystems/ucs/static/json_schema.json | 46 + .../connectors/filesystems/ucs/ucs.py | 33 + .../filesystems/unstract_file_system.py | 70 + .../filesystems/zs_dropbox/__init__.py | 12 + .../filesystems/zs_dropbox/exceptions.py | 22 + .../zs_dropbox/static/json_schema.json | 22 + .../filesystems/zs_dropbox/zs_dropbox.py | 77 + .../src/unstract/connectors/gcs_helper.py | 94 + unstract/connectors/tests/__init__.py | 0 .../tests/databases/test_bigquery_db.py | 36 + .../tests/databases/test_mariadb.py | 28 + .../tests/databases/test_mssql_db.py | 29 + .../tests/databases/test_mysql_db.py | 29 + .../tests/databases/test_postgresql_db.py | 50 + .../tests/databases/test_redshift_db.py | 34 + .../tests/databases/test_snowflake_db.py | 43 + .../tests/filesystems/test_box_fs.py | 21 + .../tests/filesystems/test_google_drive_fs.py | 23 + .../tests/filesystems/test_http_fs.py | 25 + .../tests/filesystems/test_miniofs.py | 49 + .../connectors/tests/filesystems/test_pcs.py | 27 + .../tests/filesystems/test_zs_dropbox_fs.py | 24 + .../connectors/tests/test_connectorkit.py | 26 + unstract/core/README.md | 97 + unstract/core/pyproject.toml | 30 + unstract/core/src/unstract/core/__init__.py | 0 .../src/unstract/core/llm_helper/__init__.py | 0 .../src/unstract/core/llm_helper/config.py | 54 + .../src/unstract/core/llm_helper/enums.py | 10 + .../src/unstract/core/llm_helper/llm_cache.py | 113 + .../unstract/core/llm_helper/llm_helper.py | 121 + .../src/unstract/core/llm_helper/models.py | 12 + .../version-0.1/GENERATE_CRON_STRING | 6 + .../core/llm_workflow_generator/__init__.py | 0 .../core/llm_workflow_generator/dto.py | 11 + .../llm_workflow_generator/llm_interface.py | 172 + .../prompts/azure-open-ai/version-0.1/prompt | 33 + .../core/src/unstract/core/pubsub_helper.py | 83 + unstract/core/src/unstract/core/utilities.py | 25 + .../account_services/test_pandora_account.py | 15 + .../tests/llm_helper/test_cron_string_gen.py | 41 + .../core/tests/llm_helper/test_llm_cache.py | 25 + unstract/core/tests/test_pubsub_helper.py | 21 + unstract/flags/.gitignore | 162 + unstract/flags/README.md | 72 + unstract/flags/pyproject.toml | 24 + unstract/flags/src/unstract/flags/__init__.py | 0 unstract/flags/src/unstract/flags/client.py | 86 + .../src/unstract/flags/evaluation_pb2.py | 1211 + .../src/unstract/flags/evaluation_pb2_grpc.py | 169 + .../unstract/flags/protos/evaluation.proto | 86 + unstract/flags/src/unstract/flags/sample.env | 2 + .../src/unstract/flags/tests/test_client.py | 91 + unstract/flags/tests/__init__.py | 0 unstract/tool-registry/README.md | 44 + unstract/tool-registry/pdm.lock | 3562 ++ unstract/tool-registry/pyproject.toml | 26 + .../scripts/load_tools_to_json.py | 36 + .../src/unstract/tool_registry/__init__.py | 3 + .../tool_registry/config/sample_registry.yaml | 15 + .../src/unstract/tool_registry/constants.py | 70 + .../src/unstract/tool_registry/dto.py | 397 + .../src/unstract/tool_registry/exceptions.py | 24 + .../src/unstract/tool_registry/helper.py | 365 + .../unstract/tool_registry/public_tools.json | 650 + .../tool_registry/schema_validator.py | 63 + .../unstract/tool_registry/tool_registry.py | 354 + .../src/unstract/tool_registry/tool_utils.py | 315 + .../tool-registry/tests/test_tool_registry.py | 112 + unstract/tool-sandbox/.gitignore | 162 + unstract/tool-sandbox/README.md | 1 + unstract/tool-sandbox/pyproject.toml | 22 + .../src/unstract/tool_sandbox/__init__.py | 3 + .../src/unstract/tool_sandbox/constants.py | 14 + .../src/unstract/tool_sandbox/helper.py | 131 + .../src/unstract/tool_sandbox/tool_sandbox.py | 101 + unstract/workflow-execution/.gitignore | 162 + unstract/workflow-execution/README.md | 1 + unstract/workflow-execution/pyproject.toml | 33 + .../unstract/workflow_execution/__init__.py | 3 + .../unstract/workflow_execution/constants.py | 48 + .../src/unstract/workflow_execution/dto.py | 41 + .../src/unstract/workflow_execution/enums.py | 97 + .../unstract/workflow_execution/exceptions.py | 56 + .../execution_file_handler.py | 154 + .../workflow_execution/pubsub_helper.py | 85 + .../workflow_execution/tools_utils.py | 253 + .../workflow_execution/workflow_execution.py | 414 + .../tests/sample_instances.json | 94 + .../workflow-execution/tests/workflow_test.py | 235 + worker/.gitignore | 162 + worker/README.md | 36 + worker/entrypoint.sh | 12 + worker/pdm.lock | 383 + worker/pyproject.toml | 34 + worker/requirements.txt | 5 + worker/sample.env | 10 + worker/src/unstract/worker/__init__.py | 3 + worker/src/unstract/worker/constants.py | 24 + worker/src/unstract/worker/main.py | 85 + worker/src/unstract/worker/pubsub_helper.py | 84 + worker/src/unstract/worker/worker.py | 377 + x2text-service/.gitignore | 163 + x2text-service/README.md | 54 + x2text-service/app/__init__.py | 0 .../app/authentication_middleware.py | 95 + x2text-service/app/config.py | 21 + x2text-service/app/controllers/__init__.py | 7 + x2text-service/app/controllers/controller.py | 144 + x2text-service/app/models.py | 34 + x2text-service/app/util.py | 20 + x2text-service/pdm.lock | 472 + x2text-service/pyproject.toml | 23 + x2text-service/run.py | 6 + x2text-service/sample.env | 12 + 1048 files changed, 117863 insertions(+) create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/ci-container-build.yaml create mode 100644 .github/workflows/docker-build-push-dev.yaml create mode 100644 .github/workflows/docker-tools-build-push.yaml create mode 100644 .github/workflows/production-build.yaml create mode 100644 .gitignore create mode 100644 .jshintrc create mode 100644 .pre-commit-config.yaml create mode 100644 CONTRIBUTE.md create mode 100644 README.md create mode 100644 backend/README.md create mode 100644 backend/account/ReadMe.md create mode 100644 backend/account/__init__.py create mode 100644 backend/account/admin.py create mode 100644 backend/account/api_doc.md create mode 100644 backend/account/apps.py create mode 100644 backend/account/authentication_controller.py create mode 100644 backend/account/authentication_helper.py create mode 100644 backend/account/authentication_plugin_registry.py create mode 100644 backend/account/authentication_service.py create mode 100644 backend/account/cache_service.py create mode 100644 backend/account/constants.py create mode 100644 backend/account/custom_auth_middleware.py create mode 100644 backend/account/custom_authentication.py create mode 100644 backend/account/custom_cache.py create mode 100644 backend/account/custom_exceptions.py create mode 100644 backend/account/dto.py create mode 100644 backend/account/enums.py create mode 100644 backend/account/exceptions.py create mode 100644 backend/account/migrations/0001_initial.py create mode 100644 backend/account/migrations/0002_auto_20230718_1040.py create mode 100644 backend/account/migrations/0003_platformkey.py create mode 100644 backend/account/migrations/0004_alter_platformkey_key_name_and_more.py create mode 100644 backend/account/migrations/0005_encryptionsecret.py create mode 100644 backend/account/migrations/__init__.py create mode 100644 backend/account/models.py create mode 100644 backend/account/organization.py create mode 100644 backend/account/serializer.py create mode 100644 backend/account/templates/index.html create mode 100644 backend/account/tests.py create mode 100644 backend/account/urls.py create mode 100644 backend/account/user.py create mode 100644 backend/account/views.py create mode 100644 backend/adapter_processor/__init__.py create mode 100644 backend/adapter_processor/adapter_processor.py create mode 100644 backend/adapter_processor/constants.py create mode 100644 backend/adapter_processor/exceptions.py create mode 100644 backend/adapter_processor/migrations/0001_initial.py create mode 100644 backend/adapter_processor/migrations/0002_adapterinstance_unique_adapter.py create mode 100644 backend/adapter_processor/migrations/0003_adapterinstance_adapter_metadata_b.py create mode 100644 backend/adapter_processor/migrations/0004_alter_adapterinstance_adapter_type.py create mode 100644 backend/adapter_processor/migrations/__init__.py create mode 100644 backend/adapter_processor/models.py create mode 100644 backend/adapter_processor/serializers.py create mode 100644 backend/adapter_processor/urls.py create mode 100644 backend/adapter_processor/views.py create mode 100644 backend/api/__init__.py create mode 100644 backend/api/admin.py create mode 100644 backend/api/api_deployment_views.py create mode 100644 backend/api/api_key_views.py create mode 100644 backend/api/apps.py create mode 100644 backend/api/constants.py create mode 100644 backend/api/deployment_helper.py create mode 100644 backend/api/exceptions.py create mode 100644 backend/api/key_helper.py create mode 100644 backend/api/migrations/0001_initial.py create mode 100644 backend/api/migrations/__init__.py create mode 100644 backend/api/models.py create mode 100644 backend/api/serializers.py create mode 100644 backend/api/tests.py create mode 100644 backend/api/urls.py create mode 100644 backend/apps/__init__.py create mode 100644 backend/apps/constants.py create mode 100644 backend/apps/exceptions.py create mode 100644 backend/apps/urls.py create mode 100644 backend/apps/views.py create mode 100644 backend/backend/__init__.py create mode 100644 backend/backend/asgi.py create mode 100644 backend/backend/celery.py create mode 100644 backend/backend/constants.py create mode 100644 backend/backend/exceptions.py create mode 100644 backend/backend/flowerconfig.py create mode 100644 backend/backend/public_urls.py create mode 100644 backend/backend/serializers.py create mode 100644 backend/backend/settings/__init__.py create mode 100644 backend/backend/settings/base.py create mode 100644 backend/backend/settings/dev.py create mode 100644 backend/backend/settings/test_cases.py create mode 100644 backend/backend/urls.py create mode 100644 backend/backend/wsgi.py create mode 100644 backend/connector/__init__.py create mode 100644 backend/connector/admin.py create mode 100644 backend/connector/apps.py create mode 100644 backend/connector/connector_instance_helper.py create mode 100644 backend/connector/constants.py create mode 100644 backend/connector/fields.py create mode 100644 backend/connector/migrations/0001_initial.py create mode 100644 backend/connector/migrations/0002_connectorinstance_connector_metadata_b.py create mode 100644 backend/connector/migrations/__init__.py create mode 100644 backend/connector/models.py create mode 100644 backend/connector/serializers.py create mode 100644 backend/connector/tests/conftest.py create mode 100644 backend/connector/tests/connector_tests.py create mode 100644 backend/connector/tests/fixtures/fixtures_0001.json create mode 100644 backend/connector/unstract_account.py create mode 100644 backend/connector/urls.py create mode 100644 backend/connector/views.py create mode 100644 backend/connector_auth/__init__.py create mode 100644 backend/connector_auth/admin.py create mode 100644 backend/connector_auth/apps.py create mode 100644 backend/connector_auth/constants.py create mode 100644 backend/connector_auth/exceptions.py create mode 100644 backend/connector_auth/migrations/0001_initial.py create mode 100644 backend/connector_auth/migrations/__init__.py create mode 100644 backend/connector_auth/models.py create mode 100644 backend/connector_auth/pipeline/common.py create mode 100644 backend/connector_auth/pipeline/google.py create mode 100644 backend/connector_auth/urls.py create mode 100644 backend/connector_auth/views.py create mode 100644 backend/connector_processor/__init__.py create mode 100644 backend/connector_processor/connector_processor.py create mode 100644 backend/connector_processor/constants.py create mode 100644 backend/connector_processor/exceptions.py create mode 100644 backend/connector_processor/serializers.py create mode 100644 backend/connector_processor/urls.py create mode 100644 backend/connector_processor/views.py create mode 100644 backend/cron_expression_generator/__init__.py create mode 100644 backend/cron_expression_generator/constants.py create mode 100644 backend/cron_expression_generator/descriptor.py create mode 100644 backend/cron_expression_generator/exceptions.py create mode 100644 backend/cron_expression_generator/generator.py create mode 100644 backend/cron_expression_generator/serializer.py create mode 100644 backend/cron_expression_generator/urls.py create mode 100644 backend/cron_expression_generator/views.py create mode 100644 backend/docs/__init__.py create mode 100644 backend/docs/urls.py create mode 100755 backend/entrypoint.sh create mode 100644 backend/feature_flag/__init__.py create mode 100644 backend/feature_flag/admin.py create mode 100644 backend/feature_flag/apps.py create mode 100644 backend/feature_flag/migrations/__init__.py create mode 100644 backend/feature_flag/models.py create mode 100644 backend/feature_flag/urls.py create mode 100644 backend/feature_flag/views.py create mode 100644 backend/file_management/__init__.py create mode 100644 backend/file_management/admin.py create mode 100644 backend/file_management/api_doc.md create mode 100644 backend/file_management/apps.py create mode 100644 backend/file_management/constants.py create mode 100644 backend/file_management/exceptions.py create mode 100644 backend/file_management/file_management_dto.py create mode 100644 backend/file_management/file_management_helper.py create mode 100644 backend/file_management/migrations/__init__.py create mode 100644 backend/file_management/models.py create mode 100644 backend/file_management/serializer.py create mode 100644 backend/file_management/tests.py create mode 100644 backend/file_management/urls.py create mode 100644 backend/file_management/views.py create mode 100644 backend/init.sql create mode 100644 backend/log_events/__init__.py create mode 100644 backend/log_events/admin.py create mode 100644 backend/log_events/apps.py create mode 100644 backend/log_events/constants.py create mode 100644 backend/log_events/migrations/__init__.py create mode 100644 backend/log_events/models.py create mode 100644 backend/log_events/tests.py create mode 100644 backend/log_events/urls.py create mode 100644 backend/log_events/views.py create mode 100755 backend/manage.py create mode 100644 backend/middleware/__init__.py create mode 100644 backend/middleware/exception.py create mode 100644 backend/pdm.lock create mode 100644 backend/permissions/__init__.py create mode 100644 backend/permissions/permission.py create mode 100644 backend/pipeline/__init__.py create mode 100644 backend/pipeline/constants.py create mode 100644 backend/pipeline/exceptions.py create mode 100644 backend/pipeline/manager.py create mode 100644 backend/pipeline/migrations/0001_initial.py create mode 100644 backend/pipeline/migrations/__init__.py create mode 100644 backend/pipeline/models.py create mode 100644 backend/pipeline/pipeline_processor.py create mode 100644 backend/pipeline/serializers/crud.py create mode 100644 backend/pipeline/serializers/execute.py create mode 100644 backend/pipeline/static/etl_pipelines.json create mode 100644 backend/pipeline/static/task_pipelines.json create mode 100644 backend/pipeline/urls.py create mode 100644 backend/pipeline/views.py create mode 100644 backend/platform_settings/__init__.py create mode 100644 backend/platform_settings/admin.py create mode 100644 backend/platform_settings/apps.py create mode 100644 backend/platform_settings/constants.py create mode 100644 backend/platform_settings/exceptions.py create mode 100644 backend/platform_settings/migrations/__init__.py create mode 100644 backend/platform_settings/models.py create mode 100644 backend/platform_settings/platform_auth_helper.py create mode 100644 backend/platform_settings/platform_auth_service.py create mode 100644 backend/platform_settings/serializers.py create mode 100644 backend/platform_settings/tests.py create mode 100644 backend/platform_settings/urls.py create mode 100644 backend/platform_settings/views.py create mode 100644 backend/plugins/README.md create mode 100644 backend/plugins/__init__.py create mode 100644 backend/plugins/authentication/auth_sample/__init__.py create mode 100644 backend/plugins/authentication/auth_sample/auth_helper.py create mode 100644 backend/plugins/authentication/auth_sample/auth_service.py create mode 100644 backend/plugins/authentication/auth_sample/dto.py create mode 100644 backend/plugins/authentication/auth_sample/enums.py create mode 100644 backend/plugins/authentication/auth_sample/exceptions.py create mode 100644 backend/project/__init__.py create mode 100644 backend/project/admin.py create mode 100644 backend/project/apps.py create mode 100644 backend/project/constants.py create mode 100644 backend/project/exceptions.py create mode 100644 backend/project/migrations/0001_initial.py create mode 100644 backend/project/migrations/__init__.py create mode 100644 backend/project/models.py create mode 100644 backend/project/serializers.py create mode 100644 backend/project/tests/conftest.py create mode 100644 backend/project/tests/fixtures/fixtures_0001.json create mode 100644 backend/project/tests/project_tests.py create mode 100644 backend/project/urls.py create mode 100644 backend/project/views.py create mode 100644 backend/prompt/__init__.py create mode 100644 backend/prompt/admin.py create mode 100644 backend/prompt/apps.py create mode 100644 backend/prompt/constants.py create mode 100644 backend/prompt/migrations/0001_initial.py create mode 100644 backend/prompt/migrations/__init__.py create mode 100644 backend/prompt/models.py create mode 100644 backend/prompt/serializers.py create mode 100644 backend/prompt/tests/conftest.py create mode 100644 backend/prompt/tests/fixtures/prompts_001.json create mode 100644 backend/prompt/tests/test_urls.py create mode 100644 backend/prompt/urls.py create mode 100644 backend/prompt/views.py create mode 100644 backend/prompt_studio/__init__.py create mode 100644 backend/prompt_studio/prompt_profile_manager/__init__.py create mode 100644 backend/prompt_studio/prompt_profile_manager/admin.py create mode 100644 backend/prompt_studio/prompt_profile_manager/apps.py create mode 100644 backend/prompt_studio/prompt_profile_manager/constants.py create mode 100644 backend/prompt_studio/prompt_profile_manager/exceptions.py create mode 100644 backend/prompt_studio/prompt_profile_manager/migrations/0001_initial.py create mode 100644 backend/prompt_studio/prompt_profile_manager/migrations/0002_remove_profilemanager_vector_size_and_more.py create mode 100644 backend/prompt_studio/prompt_profile_manager/migrations/0002_rename_updated_at_profilemanager_modified_at.py create mode 100644 backend/prompt_studio/prompt_profile_manager/migrations/0003_merge_20240125_0530.py create mode 100644 backend/prompt_studio/prompt_profile_manager/migrations/0004_rename_retrival_strategy_profilemanager_retrieval_strategy.py create mode 100644 backend/prompt_studio/prompt_profile_manager/migrations/0005_removed_converter_and_added_x2text_foreign_key.py create mode 100644 backend/prompt_studio/prompt_profile_manager/migrations/0006_alter_profilemanager_x2text.py create mode 100644 backend/prompt_studio/prompt_profile_manager/migrations/__init__.py create mode 100644 backend/prompt_studio/prompt_profile_manager/models.py create mode 100644 backend/prompt_studio/prompt_profile_manager/serializers.py create mode 100644 backend/prompt_studio/prompt_profile_manager/urls.py create mode 100644 backend/prompt_studio/prompt_profile_manager/views.py create mode 100644 backend/prompt_studio/prompt_studio/__init__.py create mode 100644 backend/prompt_studio/prompt_studio/admin.py create mode 100644 backend/prompt_studio/prompt_studio/apps.py create mode 100644 backend/prompt_studio/prompt_studio/constants.py create mode 100644 backend/prompt_studio/prompt_studio/exceptions.py create mode 100644 backend/prompt_studio/prompt_studio/migrations/0001_initial.py create mode 100644 backend/prompt_studio/prompt_studio/migrations/0002_prompt_eval_metrics.py create mode 100644 backend/prompt_studio/prompt_studio/migrations/0003_remove_toolstudioprompt_updated_at_and_more.py create mode 100644 backend/prompt_studio/prompt_studio/migrations/0004_alter_toolstudioprompt_prompt.py create mode 100644 backend/prompt_studio/prompt_studio/migrations/__init__.py create mode 100644 backend/prompt_studio/prompt_studio/models.py create mode 100644 backend/prompt_studio/prompt_studio/serializers.py create mode 100644 backend/prompt_studio/prompt_studio/urls.py create mode 100644 backend/prompt_studio/prompt_studio/views.py create mode 100644 backend/prompt_studio/prompt_studio_core/__init__.py create mode 100644 backend/prompt_studio/prompt_studio_core/admin.py create mode 100644 backend/prompt_studio/prompt_studio_core/apps.py create mode 100644 backend/prompt_studio/prompt_studio_core/constants.py create mode 100644 backend/prompt_studio/prompt_studio_core/exceptions.py create mode 100644 backend/prompt_studio/prompt_studio_core/migrations/0001_initial.py create mode 100644 backend/prompt_studio/prompt_studio_core/migrations/0002_alter_customtool_output.py create mode 100644 backend/prompt_studio/prompt_studio_core/migrations/0002_remove_customtool_updated_at_customtool_modified_at.py create mode 100644 backend/prompt_studio/prompt_studio_core/migrations/0003_merge_20240125_1501.py create mode 100644 backend/prompt_studio/prompt_studio_core/migrations/__init__.py create mode 100644 backend/prompt_studio/prompt_studio_core/models.py create mode 100644 backend/prompt_studio/prompt_studio_core/prompt_ide_base_tool.py create mode 100644 backend/prompt_studio/prompt_studio_core/prompt_studio_helper.py create mode 100644 backend/prompt_studio/prompt_studio_core/serializers.py create mode 100644 backend/prompt_studio/prompt_studio_core/static/select_choices.json create mode 100644 backend/prompt_studio/prompt_studio_core/urls.py create mode 100644 backend/prompt_studio/prompt_studio_core/views.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/__init__.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/admin.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/apps.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/constants.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/exceptions.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/migrations/0001_initial.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/migrations/0002_promptstudiooutputmanager_doc_name.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/migrations/0003_alter_promptstudiooutputmanager_doc_name.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/migrations/0004_alter_promptstudiooutputmanager_doc_name.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/migrations/0005_alter_promptstudiooutputmanager_profile_manager_and_more.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/migrations/0006_alter_promptstudiooutputmanager_output.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/migrations/__init__.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/models.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/serializers.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/urls.py create mode 100644 backend/prompt_studio/prompt_studio_output_manager/views.py create mode 100644 backend/prompt_studio/prompt_studio_registry/__init__.py create mode 100644 backend/prompt_studio/prompt_studio_registry/admin.py create mode 100644 backend/prompt_studio/prompt_studio_registry/apps.py create mode 100644 backend/prompt_studio/prompt_studio_registry/constants.py create mode 100644 backend/prompt_studio/prompt_studio_registry/exceptions.py create mode 100644 backend/prompt_studio/prompt_studio_registry/fields.py create mode 100644 backend/prompt_studio/prompt_studio_registry/migrations/0001_initial.py create mode 100644 backend/prompt_studio/prompt_studio_registry/migrations/0002_remove_promptstudioregistry_updated_at_and_more.py create mode 100644 backend/prompt_studio/prompt_studio_registry/migrations/0003_alter_promptstudioregistry_tool_metadata_and_more.py create mode 100644 backend/prompt_studio/prompt_studio_registry/migrations/0004_promptstudioregistry_custom_tool.py create mode 100644 backend/prompt_studio/prompt_studio_registry/migrations/0005_delete_corrupt_tool_instance.py create mode 100644 backend/prompt_studio/prompt_studio_registry/migrations/__init__.py create mode 100644 backend/prompt_studio/prompt_studio_registry/models.py create mode 100644 backend/prompt_studio/prompt_studio_registry/prompt_studio_registry_helper.py create mode 100644 backend/prompt_studio/prompt_studio_registry/serializers.py create mode 100644 backend/prompt_studio/prompt_studio_registry/static/select_choices.json create mode 100644 backend/prompt_studio/prompt_studio_registry/urls.py create mode 100644 backend/prompt_studio/prompt_studio_registry/views.py create mode 100644 backend/pyproject.toml create mode 100644 backend/sample.env create mode 100644 backend/scheduler/__init__.py create mode 100644 backend/scheduler/admin.py create mode 100644 backend/scheduler/apps.py create mode 100644 backend/scheduler/constants.py create mode 100644 backend/scheduler/exceptions.py create mode 100644 backend/scheduler/helper.py create mode 100644 backend/scheduler/serializer.py create mode 100644 backend/scheduler/settings.py create mode 100644 backend/scheduler/tasks.py create mode 100644 backend/scheduler/views.py create mode 100644 backend/tenant_account/__init__.py create mode 100644 backend/tenant_account/admin.py create mode 100644 backend/tenant_account/apps.py create mode 100644 backend/tenant_account/constants.py create mode 100644 backend/tenant_account/dto.py create mode 100644 backend/tenant_account/enums.py create mode 100644 backend/tenant_account/invitation_urls.py create mode 100644 backend/tenant_account/invitation_views.py create mode 100644 backend/tenant_account/migrations/0001_initial.py create mode 100644 backend/tenant_account/migrations/0002_organizationmember_delete_user.py create mode 100644 backend/tenant_account/migrations/0003_alter_organizationmember_options_and_more.py create mode 100644 backend/tenant_account/migrations/0004_alter_organizationmember_member_id.py create mode 100644 backend/tenant_account/migrations/__init__.py create mode 100644 backend/tenant_account/models.py create mode 100644 backend/tenant_account/organization_member_service.py create mode 100644 backend/tenant_account/serializer.py create mode 100644 backend/tenant_account/templates/land.html create mode 100644 backend/tenant_account/tests.py create mode 100644 backend/tenant_account/urls.py create mode 100644 backend/tenant_account/users_urls.py create mode 100644 backend/tenant_account/users_view.py create mode 100644 backend/tenant_account/views.py create mode 100644 backend/tool_instance/__init__.py create mode 100644 backend/tool_instance/admin.py create mode 100644 backend/tool_instance/apps.py create mode 100644 backend/tool_instance/constants.py create mode 100644 backend/tool_instance/exceptions.py create mode 100644 backend/tool_instance/migrations/0001_initial.py create mode 100644 backend/tool_instance/migrations/__init__.py create mode 100644 backend/tool_instance/models.py create mode 100644 backend/tool_instance/serializers.py create mode 100644 backend/tool_instance/tests.py create mode 100644 backend/tool_instance/tool_instance_helper.py create mode 100644 backend/tool_instance/tool_processor.py create mode 100644 backend/tool_instance/urls.py create mode 100644 backend/tool_instance/views.py create mode 100644 backend/utils/__init__.py create mode 100644 backend/utils/common_utils.py create mode 100644 backend/utils/constants.py create mode 100644 backend/utils/filtering.py create mode 100644 backend/utils/models/base_model.py create mode 100644 backend/utils/request/__init__.py create mode 100644 backend/utils/request/constants.py create mode 100644 backend/utils/request/feature_flag.py create mode 100644 backend/utils/request/request.py create mode 100644 backend/utils/seed_data/README.md create mode 100644 backend/utils/seed_data/seed_data.py create mode 100644 backend/utils/serializer_utils.py create mode 100644 backend/workflow_manager/__init__.py create mode 100644 backend/workflow_manager/endpoint/__init__.py create mode 100644 backend/workflow_manager/endpoint/admin.py create mode 100644 backend/workflow_manager/endpoint/apps.py create mode 100644 backend/workflow_manager/endpoint/base_connector.py create mode 100644 backend/workflow_manager/endpoint/constants.py create mode 100644 backend/workflow_manager/endpoint/database_utils.py create mode 100644 backend/workflow_manager/endpoint/destination.py create mode 100644 backend/workflow_manager/endpoint/endpoint_utils.py create mode 100644 backend/workflow_manager/endpoint/exceptions.py create mode 100644 backend/workflow_manager/endpoint/migrations/0001_initial.py create mode 100644 backend/workflow_manager/endpoint/migrations/__init__.py create mode 100644 backend/workflow_manager/endpoint/models.py create mode 100644 backend/workflow_manager/endpoint/serializers.py create mode 100644 backend/workflow_manager/endpoint/source.py create mode 100644 backend/workflow_manager/endpoint/static/dest/db.json create mode 100644 backend/workflow_manager/endpoint/static/dest/file.json create mode 100644 backend/workflow_manager/endpoint/static/src/api.json create mode 100644 backend/workflow_manager/endpoint/static/src/file.json create mode 100644 backend/workflow_manager/endpoint/tests.py create mode 100644 backend/workflow_manager/endpoint/urls.py create mode 100644 backend/workflow_manager/endpoint/views.py create mode 100644 backend/workflow_manager/urls.py create mode 100644 backend/workflow_manager/workflow/__init__.py create mode 100644 backend/workflow_manager/workflow/admin.py create mode 100644 backend/workflow_manager/workflow/apps.py create mode 100644 backend/workflow_manager/workflow/constants.py create mode 100644 backend/workflow_manager/workflow/dto.py create mode 100644 backend/workflow_manager/workflow/enums.py create mode 100644 backend/workflow_manager/workflow/exceptions.py create mode 100644 backend/workflow_manager/workflow/execution.py create mode 100644 backend/workflow_manager/workflow/file_history_helper.py create mode 100644 backend/workflow_manager/workflow/generator.py create mode 100644 backend/workflow_manager/workflow/migrations/0001_initial.py create mode 100644 backend/workflow_manager/workflow/migrations/__init__.py create mode 100644 backend/workflow_manager/workflow/models/__init__.py create mode 100644 backend/workflow_manager/workflow/models/execution.py create mode 100644 backend/workflow_manager/workflow/models/file_history.py create mode 100644 backend/workflow_manager/workflow/models/workflow.py create mode 100644 backend/workflow_manager/workflow/serializers.py create mode 100644 backend/workflow_manager/workflow/tests.py create mode 100644 backend/workflow_manager/workflow/urls.py create mode 100644 backend/workflow_manager/workflow/views.py create mode 100644 backend/workflow_manager/workflow/workflow_helper.py create mode 100644 docker/README.md create mode 100644 docker/docker-compose-dev-essentials.yaml create mode 100644 docker/docker-compose.build.yaml create mode 100644 docker/docker-compose.yaml create mode 100644 docker/dockerfiles/backend.Dockerfile create mode 100644 docker/dockerfiles/backend.Dockerfile.dockerignore create mode 100644 docker/dockerfiles/document.Dockerfile create mode 100644 docker/dockerfiles/document.Dockerfile.dockerignore create mode 100644 docker/dockerfiles/frontend.Dockerfile create mode 100644 docker/dockerfiles/frontend.Dockerfile.dockerignore create mode 100644 docker/dockerfiles/platform.Dockerfile create mode 100644 docker/dockerfiles/platform.Dockerfile.dockerignore create mode 100644 docker/dockerfiles/prompt.Dockerfile create mode 100644 docker/dockerfiles/prompt.Dockerfile.dockerignore create mode 100644 docker/dockerfiles/worker.Dockerfile create mode 100644 docker/dockerfiles/worker.Dockerfile.dockerignore create mode 100644 docker/dockerfiles/x2text.Dockerfile create mode 100644 docker/dockerfiles/x2text.Dockerfile.dockerignore create mode 100644 docker/sample.essentials.env create mode 100644 docker/sample.proxy_overrides.yaml create mode 100755 docker/scripts/check_container_exited.sh create mode 100755 docker/scripts/deploy.sh create mode 100755 docker/scripts/resolve_container_svc_from_host.sh create mode 100644 document-service/.gitignore create mode 100644 document-service/README.md create mode 100644 document-service/pdm.lock create mode 100644 document-service/pyproject.toml create mode 100644 document-service/sample.env create mode 100644 document-service/src/unstract/document_service/__init__.py create mode 100644 document-service/src/unstract/document_service/main.py create mode 100644 document-service/tests/__init__.py create mode 100644 document-service/thunder-collection_document-service.json create mode 100755 document-service/wrapper.sh create mode 100644 frontend/.eslintrc.json create mode 100644 frontend/.gitignore create mode 100644 frontend/README.md create mode 100644 frontend/nginx.conf create mode 100644 frontend/package-lock.json create mode 100644 frontend/package.json create mode 100644 frontend/public/favicon.ico create mode 100644 frontend/public/index.html create mode 100644 frontend/public/manifest.json create mode 100644 frontend/sample.env create mode 100644 frontend/src/App.jsx create mode 100644 frontend/src/assets/BingAds.svg create mode 100644 frontend/src/assets/Unstract.svg create mode 100644 frontend/src/assets/UnstractLogoBlack.svg create mode 100644 frontend/src/assets/Workflows.svg create mode 100644 frontend/src/assets/api-deployments.svg create mode 100644 frontend/src/assets/appdev.svg create mode 100644 frontend/src/assets/assertion.svg create mode 100644 frontend/src/assets/bg_shape.svg create mode 100644 frontend/src/assets/combined-output.svg create mode 100644 frontend/src/assets/connect_embedding.svg create mode 100644 frontend/src/assets/connect_llm.svg create mode 100644 frontend/src/assets/connect_vector_db.svg create mode 100644 frontend/src/assets/custom-tools-icon.svg create mode 100644 frontend/src/assets/document.svg create mode 100644 frontend/src/assets/embedding.svg create mode 100644 frontend/src/assets/empty.svg create mode 100644 frontend/src/assets/etl.svg create mode 100644 frontend/src/assets/folder.svg create mode 100644 frontend/src/assets/index.js create mode 100644 frontend/src/assets/input-placeholder.svg create mode 100644 frontend/src/assets/landing_bg.png create mode 100644 frontend/src/assets/landing_bg.svg create mode 100644 frontend/src/assets/list-of-tools-placeholder.svg create mode 100644 frontend/src/assets/list-of-wf-steps-placeholder.svg create mode 100644 frontend/src/assets/llm.svg create mode 100644 frontend/src/assets/login-page-bg.svg create mode 100644 frontend/src/assets/loginPageSS.webp create mode 100644 frontend/src/assets/logo-24.svg create mode 100644 frontend/src/assets/logo-64.svg create mode 100644 frontend/src/assets/moon-icon.svg create mode 100644 frontend/src/assets/output-placeholder.svg create mode 100644 frontend/src/assets/platform-settings.svg create mode 100644 frontend/src/assets/steps.svg create mode 100644 frontend/src/assets/sun-icon.svg create mode 100644 frontend/src/assets/swatch.svg create mode 100644 frontend/src/assets/task.svg create mode 100644 frontend/src/assets/tool-ide-input-document-placeholder.svg create mode 100644 frontend/src/assets/tool-ide-prompts-placeholder.svg create mode 100644 frontend/src/assets/tool.svg create mode 100644 frontend/src/assets/vector-db.svg create mode 100644 frontend/src/components/agency/actions/Actions.css create mode 100644 frontend/src/components/agency/actions/Actions.jsx create mode 100644 frontend/src/components/agency/agency/Agency.css create mode 100644 frontend/src/components/agency/agency/Agency.jsx create mode 100644 frontend/src/components/agency/cards-list/CardList.css create mode 100644 frontend/src/components/agency/cards-list/CardsList.jsx create mode 100644 frontend/src/components/agency/configuration-modal/ConfigurationModal.css create mode 100644 frontend/src/components/agency/configuration-modal/ConfigurationModal.jsx create mode 100644 frontend/src/components/agency/configuration/Configuration.css create mode 100644 frontend/src/components/agency/configuration/Configuration.jsx create mode 100644 frontend/src/components/agency/configure-connector-modal/ConfigureConnectorModal.css create mode 100644 frontend/src/components/agency/configure-connector-modal/ConfigureConnectorModal.jsx create mode 100644 frontend/src/components/agency/configure-forms-layout/ConfigureFormsLayout.jsx create mode 100644 frontend/src/components/agency/ds-settings-card/DsSettingsCard.jsx create mode 100644 frontend/src/components/agency/file-upload/FileUpload.jsx create mode 100644 frontend/src/components/agency/input-output/InputOutput.css create mode 100644 frontend/src/components/agency/input-output/InputOutput.jsx create mode 100644 frontend/src/components/agency/list-of-connectors/ListOfConnectors.jsx create mode 100644 frontend/src/components/agency/list-of-tools/ListOfTools.css create mode 100644 frontend/src/components/agency/list-of-tools/ListOfTools.jsx create mode 100644 frontend/src/components/agency/logs-label/LogsLabel.css create mode 100644 frontend/src/components/agency/logs-label/LogsLabel.jsx create mode 100644 frontend/src/components/agency/markdown-renderer/MarkdownRenderer.css create mode 100644 frontend/src/components/agency/markdown-renderer/MarkdownRenderer.jsx create mode 100644 frontend/src/components/agency/prompt/Prompt.css create mode 100644 frontend/src/components/agency/prompt/Prompt.jsx create mode 100644 frontend/src/components/agency/settings-form/SettingsForm.jsx create mode 100644 frontend/src/components/agency/side-panel/SidePanel.css create mode 100644 frontend/src/components/agency/side-panel/SidePanel.jsx create mode 100644 frontend/src/components/agency/step-card/StepCard.css create mode 100644 frontend/src/components/agency/step-card/StepCard.jsx create mode 100644 frontend/src/components/agency/steps/Steps.css create mode 100644 frontend/src/components/agency/steps/Steps.jsx create mode 100644 frontend/src/components/agency/tool-icon/ToolIcon.css create mode 100644 frontend/src/components/agency/tool-icon/ToolIcon.jsx create mode 100644 frontend/src/components/agency/tool-info-card/ToolInfoCard.css create mode 100644 frontend/src/components/agency/tool-info-card/ToolInfoCard.jsx create mode 100644 frontend/src/components/agency/tool-settings/ToolSettings.css create mode 100644 frontend/src/components/agency/tool-settings/ToolSettings.jsx create mode 100644 frontend/src/components/agency/tools/Tools.css create mode 100644 frontend/src/components/agency/tools/Tools.jsx create mode 100644 frontend/src/components/agency/workflow-execution-layout/WorkflowExecutionMain.css create mode 100644 frontend/src/components/agency/workflow-execution-layout/WorkflowExecutionMain.jsx create mode 100644 frontend/src/components/agency/workflow-execution/WorkflowExecution.css create mode 100644 frontend/src/components/agency/workflow-execution/WorkflowExecution.jsx create mode 100644 frontend/src/components/agency/workflow-execution/workflow_actions.js create mode 100644 frontend/src/components/custom-tools/add-custom-tool-form-modal/AddCustomToolFormModal.css create mode 100644 frontend/src/components/custom-tools/add-custom-tool-form-modal/AddCustomToolFormModal.jsx create mode 100644 frontend/src/components/custom-tools/add-llm-profile-modal/AddLlmProfileModal.css create mode 100644 frontend/src/components/custom-tools/add-llm-profile-modal/AddLlmProfileModal.jsx create mode 100644 frontend/src/components/custom-tools/combined-output/CombinedOutput.css create mode 100644 frontend/src/components/custom-tools/combined-output/CombinedOutput.jsx create mode 100644 frontend/src/components/custom-tools/custom-synonyms-modal/CustomSynonymsModal.css create mode 100644 frontend/src/components/custom-tools/custom-synonyms-modal/CustomSynonymsModal.jsx create mode 100644 frontend/src/components/custom-tools/custom-synonyms/CustomSynonyms.css create mode 100644 frontend/src/components/custom-tools/custom-synonyms/CustomSynonyms.jsx create mode 100644 frontend/src/components/custom-tools/display-logs/DisplayLogs.css create mode 100644 frontend/src/components/custom-tools/display-logs/DisplayLogs.jsx create mode 100644 frontend/src/components/custom-tools/document-manager/DocumentManager.css create mode 100644 frontend/src/components/custom-tools/document-manager/DocumentManager.jsx create mode 100644 frontend/src/components/custom-tools/document-parser/DocumentParser.css create mode 100644 frontend/src/components/custom-tools/document-parser/DocumentParser.jsx create mode 100644 frontend/src/components/custom-tools/edit-tool-info/EditToolInfo.css create mode 100644 frontend/src/components/custom-tools/edit-tool-info/EditToolInfo.jsx create mode 100644 frontend/src/components/custom-tools/editable-text/EditableText.css create mode 100644 frontend/src/components/custom-tools/editable-text/EditableText.jsx create mode 100644 frontend/src/components/custom-tools/eval-metric-tag/EvalMetricTag.css create mode 100644 frontend/src/components/custom-tools/eval-metric-tag/EvalMetricTag.jsx create mode 100644 frontend/src/components/custom-tools/eval-modal/EvalModal.jsx create mode 100644 frontend/src/components/custom-tools/footer-layout/FooterLayout.css create mode 100644 frontend/src/components/custom-tools/footer-layout/FooterLayout.jsx create mode 100644 frontend/src/components/custom-tools/footer/Footer.css create mode 100644 frontend/src/components/custom-tools/footer/Footer.jsx create mode 100644 frontend/src/components/custom-tools/generate-index/GenerateIndex.css create mode 100644 frontend/src/components/custom-tools/generate-index/GenerateIndex.jsx create mode 100644 frontend/src/components/custom-tools/header/Header.css create mode 100644 frontend/src/components/custom-tools/header/Header.jsx create mode 100644 frontend/src/components/custom-tools/list-of-tools/ListOfTools.css create mode 100644 frontend/src/components/custom-tools/list-of-tools/ListOfTools.jsx create mode 100644 frontend/src/components/custom-tools/manage-docs-modal/ManageDocsModal.css create mode 100644 frontend/src/components/custom-tools/manage-docs-modal/ManageDocsModal.jsx create mode 100644 frontend/src/components/custom-tools/manage-llm-profiles-modal/ManageLlmProfilesModal.jsx create mode 100644 frontend/src/components/custom-tools/manage-llm-profiles/ManageLlmProfiles.css create mode 100644 frontend/src/components/custom-tools/manage-llm-profiles/ManageLlmProfiles.jsx create mode 100644 frontend/src/components/custom-tools/notes-card/NotesCard.css create mode 100644 frontend/src/components/custom-tools/notes-card/NotesCard.jsx create mode 100644 frontend/src/components/custom-tools/output-for-doc-modal/OutputForDocModal.css create mode 100644 frontend/src/components/custom-tools/output-for-doc-modal/OutputForDocModal.jsx create mode 100644 frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx create mode 100644 frontend/src/components/custom-tools/pre-and-post-amble-modal/PreAndPostAmbleModal.css create mode 100644 frontend/src/components/custom-tools/pre-and-post-amble-modal/PreAndPostAmbleModal.jsx create mode 100644 frontend/src/components/custom-tools/prompt-card/PromptCard.css create mode 100644 frontend/src/components/custom-tools/prompt-card/PromptCard.jsx create mode 100644 frontend/src/components/custom-tools/tool-ide/ToolIde.css create mode 100644 frontend/src/components/custom-tools/tool-ide/ToolIde.jsx create mode 100644 frontend/src/components/custom-tools/tools-main/ToolsMain.css create mode 100644 frontend/src/components/custom-tools/tools-main/ToolsMain.jsx create mode 100644 frontend/src/components/custom-tools/view-tools/ViewTools.css create mode 100644 frontend/src/components/custom-tools/view-tools/ViewTools.jsx create mode 100644 frontend/src/components/deployments/api-deployment/ApiDeployment.jsx create mode 100644 frontend/src/components/deployments/api-deployment/api-deployments-service.js create mode 100644 frontend/src/components/deployments/body/Body.jsx create mode 100644 frontend/src/components/deployments/create-api-deployment-modal/CreateApiDeploymentModal.jsx create mode 100644 frontend/src/components/deployments/delete-modal/DeleteModal.jsx create mode 100644 frontend/src/components/deployments/display-code/CodeSnippet.css create mode 100644 frontend/src/components/deployments/display-code/CodeSnippet.jsx create mode 100644 frontend/src/components/deployments/display-code/DisplayCode.css create mode 100644 frontend/src/components/deployments/display-code/DisplayCode.jsx create mode 100644 frontend/src/components/deployments/header/Header.jsx create mode 100644 frontend/src/components/deployments/layout/Layout.css create mode 100644 frontend/src/components/deployments/layout/Layout.jsx create mode 100644 frontend/src/components/deployments/manage-keys/ManageKeys.css create mode 100644 frontend/src/components/deployments/manage-keys/ManageKeys.jsx create mode 100644 frontend/src/components/error/GenericError/GenericError.jsx create mode 100644 frontend/src/components/error/NotFound/NotFound.css create mode 100644 frontend/src/components/error/NotFound/NotFound.jsx create mode 100644 frontend/src/components/error/UnAuthorized/Unauthorized.css create mode 100644 frontend/src/components/error/UnAuthorized/Unauthorized.jsx create mode 100644 frontend/src/components/helpers/auth/PersistentLogin.js create mode 100644 frontend/src/components/helpers/auth/RequireAdmin.js create mode 100644 frontend/src/components/helpers/auth/RequireAuth.js create mode 100644 frontend/src/components/helpers/auth/RequireGuest.js create mode 100644 frontend/src/components/helpers/custom-tools/CustomToolsHelper.js create mode 100644 frontend/src/components/helpers/project/ProjectHelper.js create mode 100644 frontend/src/components/helpers/socket-messages/SocketMessages.js create mode 100644 frontend/src/components/input-output/add-source-modal/AddSourceModa.css create mode 100644 frontend/src/components/input-output/add-source-modal/AddSourceModal.jsx create mode 100644 frontend/src/components/input-output/add-source/AddSource.css create mode 100644 frontend/src/components/input-output/add-source/AddSource.jsx create mode 100644 frontend/src/components/input-output/configure-ds/ConfigureDs.css create mode 100644 frontend/src/components/input-output/configure-ds/ConfigureDs.jsx create mode 100644 frontend/src/components/input-output/data-source-card/DataSourceCard.css create mode 100644 frontend/src/components/input-output/data-source-card/DataSourceCard.jsx create mode 100644 frontend/src/components/input-output/edit-ds-modal/EditDsModal.css create mode 100644 frontend/src/components/input-output/edit-ds-modal/EditDsModal.jsx create mode 100644 frontend/src/components/input-output/file-system/FileSystem.css create mode 100644 frontend/src/components/input-output/file-system/FileSystem.jsx create mode 100644 frontend/src/components/input-output/input-output/InputOutput.css create mode 100644 frontend/src/components/input-output/input-output/InputOutput.jsx create mode 100644 frontend/src/components/input-output/input-output/input-service.js create mode 100644 frontend/src/components/input-output/list-of-sources/ListOfSources.css create mode 100644 frontend/src/components/input-output/list-of-sources/ListOfSources.jsx create mode 100644 frontend/src/components/input-output/manage-files/ManageFiles.css create mode 100644 frontend/src/components/input-output/manage-files/ManageFiles.jsx create mode 100644 frontend/src/components/input-output/sidebar/Sidebar.css create mode 100644 frontend/src/components/input-output/sidebar/Sidebar.jsx create mode 100644 frontend/src/components/log-in/Login.css create mode 100644 frontend/src/components/log-in/Login.jsx create mode 100644 frontend/src/components/navigations/side-nav-bar/SideNavBar.css create mode 100644 frontend/src/components/navigations/side-nav-bar/SideNavBar.jsx create mode 100644 frontend/src/components/navigations/top-nav-bar/TopNavBar.css create mode 100644 frontend/src/components/navigations/top-nav-bar/TopNavBar.jsx create mode 100644 frontend/src/components/oauth-ds/google/GoogleOAuthButton.css create mode 100644 frontend/src/components/oauth-ds/google/GoogleOAuthButton.jsx create mode 100644 frontend/src/components/oauth-ds/oauth-ds/OAuthDs.jsx create mode 100644 frontend/src/components/oauth-ds/oauth-status/OAuthStatus.css create mode 100644 frontend/src/components/oauth-ds/oauth-status/OAuthStatus.jsx create mode 100644 frontend/src/components/onboard/OnBoard.jsx create mode 100644 frontend/src/components/onboard/onBoard.css create mode 100644 frontend/src/components/pipelines-or-deployments/app-deploy/AppDeploy.jsx create mode 100644 frontend/src/components/pipelines-or-deployments/delete-modal/DeleteModal.jsx create mode 100644 frontend/src/components/pipelines-or-deployments/etl-task-deploy/EtlTaskDeploy.css create mode 100644 frontend/src/components/pipelines-or-deployments/etl-task-deploy/EtlTaskDeploy.jsx create mode 100644 frontend/src/components/pipelines-or-deployments/header/Header.css create mode 100644 frontend/src/components/pipelines-or-deployments/header/Header.jsx create mode 100644 frontend/src/components/pipelines-or-deployments/pipelines-or-deployments/PipelinesOrDeployments.css create mode 100644 frontend/src/components/pipelines-or-deployments/pipelines-or-deployments/PipelinesOrDeployments.jsx create mode 100644 frontend/src/components/pipelines-or-deployments/pipelines/Pipelines.css create mode 100644 frontend/src/components/pipelines-or-deployments/pipelines/Pipelines.jsx create mode 100644 frontend/src/components/profile/Profile.css create mode 100644 frontend/src/components/profile/Profile.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/alt-date-time-widget/AltDateTimeWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/alt-date-widget/AltDateWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/array-field/ArrayField.css create mode 100644 frontend/src/components/rjsf-custom-widgets/array-field/ArrayField.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/checkbox-widget/CheckboxWidget.css create mode 100644 frontend/src/components/rjsf-custom-widgets/checkbox-widget/CheckboxWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/checkboxes-widget/CheckboxesWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/color-widget/ColorWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/date-time-widget/DateTimeWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/date-widget/DateWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/email-widget/EmailWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/file-widget/FileWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/hidden-widget/HiddenWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/password-widget/PasswordWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/select-widget/SelectWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/text-widget/TextWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/time-widget/TimeWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/up-down-widget/UpDownWidget.jsx create mode 100644 frontend/src/components/rjsf-custom-widgets/url-widget/URLWidget.jsx create mode 100644 frontend/src/components/settings/default-triad/DefaultTriad.css create mode 100644 frontend/src/components/settings/default-triad/DefaultTriad.jsx create mode 100644 frontend/src/components/settings/invite/InviteEditUser.css create mode 100644 frontend/src/components/settings/invite/InviteEditUser.jsx create mode 100644 frontend/src/components/settings/platform/PlatformSettings.css create mode 100644 frontend/src/components/settings/platform/PlatformSettings.jsx create mode 100644 frontend/src/components/settings/settings/Settings.css create mode 100644 frontend/src/components/settings/settings/Settings.jsx create mode 100644 frontend/src/components/settings/users/Users.css create mode 100644 frontend/src/components/settings/users/Users.jsx create mode 100644 frontend/src/components/tool-settings/list-of-items/ListOfItems.css create mode 100644 frontend/src/components/tool-settings/list-of-items/ListOfItems.jsx create mode 100644 frontend/src/components/tool-settings/tool-settings/ToolSettings.css create mode 100644 frontend/src/components/tool-settings/tool-settings/ToolSettings.jsx create mode 100644 frontend/src/components/widgets/confirm-modal/ConfirmModal.jsx create mode 100644 frontend/src/components/widgets/custom-button/CustomButton.css create mode 100644 frontend/src/components/widgets/custom-button/CustomButton.jsx create mode 100644 frontend/src/components/widgets/empty-state/EmptyState.jsx create mode 100644 frontend/src/components/widgets/error-boundary/ErrorBoundary.jsx create mode 100644 frontend/src/components/widgets/grid-view/GridView.css create mode 100644 frontend/src/components/widgets/grid-view/GridView.jsx create mode 100644 frontend/src/components/widgets/lazy-loader/LazyLoader.jsx create mode 100644 frontend/src/components/widgets/list-view/ListView.css create mode 100644 frontend/src/components/widgets/list-view/ListView.jsx create mode 100644 frontend/src/components/widgets/space-wrapper/SpaceWrapper.jsx create mode 100644 frontend/src/components/widgets/spinner-loader/SpinnerLoader.css create mode 100644 frontend/src/components/widgets/spinner-loader/SpinnerLoader.jsx create mode 100644 frontend/src/components/widgets/top-bar/TopBar.css create mode 100644 frontend/src/components/widgets/top-bar/TopBar.jsx create mode 100644 frontend/src/components/workflows/new-workflow/NewWorkflow.jsx create mode 100644 frontend/src/components/workflows/workflow/Workflows.css create mode 100644 frontend/src/components/workflows/workflow/Workflows.jsx create mode 100644 frontend/src/components/workflows/workflow/workflow-service.js create mode 100644 frontend/src/helpers/GetSessionData.js create mode 100644 frontend/src/helpers/GetStaticData.js create mode 100644 frontend/src/helpers/SocketContext.js create mode 100644 frontend/src/hooks/useAxiosPrivate.js create mode 100644 frontend/src/hooks/useLogout.js create mode 100644 frontend/src/hooks/useSessionValid.js create mode 100644 frontend/src/index.css create mode 100644 frontend/src/index.js create mode 100644 frontend/src/layouts/content-center-layout/ContentCenterLayout.css create mode 100644 frontend/src/layouts/content-center-layout/ContentCenterLayout.jsx create mode 100644 frontend/src/layouts/fullpage-payout/FullPageLayout.css create mode 100644 frontend/src/layouts/fullpage-payout/FullPageLayout.jsx create mode 100644 frontend/src/layouts/island-layout/IslandLayout.css create mode 100644 frontend/src/layouts/island-layout/IslandLayout.jsx create mode 100644 frontend/src/layouts/menu-layout/MenuLayout.css create mode 100644 frontend/src/layouts/menu-layout/MenuLayout.jsx create mode 100644 frontend/src/layouts/page-layout/PageLayout.css create mode 100644 frontend/src/layouts/page-layout/PageLayout.jsx create mode 100644 frontend/src/layouts/rjsf-form-layout/RjsfFormLayout.css create mode 100644 frontend/src/layouts/rjsf-form-layout/RjsfFormLayout.jsx create mode 100644 frontend/src/layouts/rjsf-widget-layout/RjsfWidgetLayout.css create mode 100644 frontend/src/layouts/rjsf-widget-layout/RjsfWidgetLayout.jsx create mode 100644 frontend/src/pages/AgencyPage.jsx create mode 100644 frontend/src/pages/AppDevelopmentPage.jsx create mode 100644 frontend/src/pages/CustomTools.jsx create mode 100644 frontend/src/pages/DeploymentsPage.jsx create mode 100644 frontend/src/pages/InputOutputPage.jsx create mode 100644 frontend/src/pages/InviteEditUserPage.jsx create mode 100644 frontend/src/pages/LandingPage.jsx create mode 100644 frontend/src/pages/OnBoardPage.jsx create mode 100644 frontend/src/pages/PipelinesOrDeploymentsPage.jsx create mode 100644 frontend/src/pages/ProfilePage.jsx create mode 100644 frontend/src/pages/SettingsPage.jsx create mode 100644 frontend/src/pages/ToolIdePage.jsx create mode 100644 frontend/src/pages/ToolsSettingsPage.jsx create mode 100644 frontend/src/pages/UsersPage.jsx create mode 100644 frontend/src/pages/WorkflowsPage.jsx create mode 100644 frontend/src/routes/Router.jsx create mode 100644 frontend/src/setupProxy.js create mode 100644 frontend/src/setupTests.js create mode 100644 frontend/src/store/alert-store.js create mode 100644 frontend/src/store/custom-tool-store.js create mode 100644 frontend/src/store/session-store.js create mode 100644 frontend/src/store/socket-logs-store.js create mode 100644 frontend/src/store/socket-messages-store.js create mode 100644 frontend/src/store/tool-settings.js create mode 100644 frontend/src/store/workflow-store.js create mode 100644 frontend/src/variables.css create mode 100644 pdm.lock create mode 100644 platform-service/.gitignore create mode 100644 platform-service/README.md create mode 100644 platform-service/pdm.lock create mode 100644 platform-service/pyproject.toml create mode 100644 platform-service/sample.env create mode 100644 platform-service/src/unstract/platform_service/__init__.py create mode 100644 platform-service/src/unstract/platform_service/exceptions.py create mode 100644 platform-service/src/unstract/platform_service/helper.py create mode 100644 platform-service/src/unstract/platform_service/main.py create mode 100644 platform-service/tests/test_auth_middleware.py create mode 100644 prompt-service/.gitignore create mode 100644 prompt-service/README.md create mode 100644 prompt-service/pdm.lock create mode 100644 prompt-service/pyproject.toml create mode 100644 prompt-service/sample.env create mode 100644 prompt-service/src/unstract/prompt_service/__init__.py create mode 100644 prompt-service/src/unstract/prompt_service/authentication_middleware.py create mode 100644 prompt-service/src/unstract/prompt_service/constants.py create mode 100644 prompt-service/src/unstract/prompt_service/helper.py create mode 100644 prompt-service/src/unstract/prompt_service/main.py create mode 100644 prompt-service/src/unstract/prompt_service/prompt_ide_base_tool.py create mode 100644 pyproject.toml create mode 100644 tools/README.md create mode 100644 tools/classifier/.dockerignore create mode 100644 tools/classifier/Dockerfile create mode 100644 tools/classifier/README.md create mode 100644 tools/classifier/__init__.py create mode 100644 tools/classifier/requirements.txt create mode 100644 tools/classifier/sample.env create mode 100644 tools/classifier/src/config/icon.svg create mode 100644 tools/classifier/src/config/properties.json create mode 100644 tools/classifier/src/config/runtime_variables.json create mode 100644 tools/classifier/src/config/spec.json create mode 100644 tools/classifier/src/helper.py create mode 100644 tools/classifier/src/main.py create mode 100644 tools/doc_pii_redactor/.dockerignore create mode 100644 tools/doc_pii_redactor/Dockerfile create mode 100644 tools/doc_pii_redactor/README.md create mode 100644 tools/doc_pii_redactor/__init__.py create mode 100644 tools/doc_pii_redactor/requirements.txt create mode 100644 tools/doc_pii_redactor/sample.env create mode 100644 tools/doc_pii_redactor/src/config/icon.svg create mode 100644 tools/doc_pii_redactor/src/config/properties.json create mode 100644 tools/doc_pii_redactor/src/config/runtime_variables.json create mode 100644 tools/doc_pii_redactor/src/config/spec.json create mode 100644 tools/doc_pii_redactor/src/doc_pii_redactor/__init__.py create mode 100644 tools/doc_pii_redactor/src/doc_pii_redactor/constants.py create mode 100644 tools/doc_pii_redactor/src/doc_pii_redactor/enums.py create mode 100644 tools/doc_pii_redactor/src/doc_pii_redactor/helper.py create mode 100644 tools/doc_pii_redactor/src/main.py create mode 100644 tools/indexer/.dockerignore create mode 100644 tools/indexer/Dockerfile create mode 100644 tools/indexer/README.md create mode 100644 tools/indexer/__init__.py create mode 100644 tools/indexer/requirements.txt create mode 100644 tools/indexer/sample.env create mode 100644 tools/indexer/src/config/icon.svg create mode 100644 tools/indexer/src/config/properties.json create mode 100644 tools/indexer/src/config/runtime_variables.json create mode 100644 tools/indexer/src/config/spec.json create mode 100644 tools/indexer/src/constants.py create mode 100644 tools/indexer/src/main.py create mode 100644 tools/structure/.dockerignore create mode 100644 tools/structure/Dockerfile create mode 100644 tools/structure/README.md create mode 100644 tools/structure/__init__.py create mode 100644 tools/structure/requirements.txt create mode 100644 tools/structure/sample.env create mode 100644 tools/structure/src/config/icon.svg create mode 100644 tools/structure/src/config/properties.json create mode 100644 tools/structure/src/config/runtime_variables.json create mode 100644 tools/structure/src/config/spec.json create mode 100644 tools/structure/src/constants.py create mode 100644 tools/structure/src/main.py create mode 100644 tools/text_extractor/.dockerignore create mode 100644 tools/text_extractor/.gitignore create mode 100644 tools/text_extractor/Dockerfile create mode 100644 tools/text_extractor/README.md create mode 100644 tools/text_extractor/__init__.py create mode 100644 tools/text_extractor/requirements.txt create mode 100644 tools/text_extractor/sample.env create mode 100644 tools/text_extractor/src/config/icon.svg create mode 100644 tools/text_extractor/src/config/properties.json create mode 100644 tools/text_extractor/src/config/runtime_variables.json create mode 100644 tools/text_extractor/src/config/spec.json create mode 100644 tools/text_extractor/src/example_package/__init__.py create mode 100644 tools/text_extractor/src/main.py create mode 100644 tools/text_extractor/tests/__init__.py create mode 100644 tools/translate/.dockerignore create mode 100644 tools/translate/Dockerfile create mode 100644 tools/translate/README.md create mode 100644 tools/translate/__init__.py create mode 100644 tools/translate/requirements.txt create mode 100644 tools/translate/sample.env create mode 100644 tools/translate/src/config/icon.svg create mode 100644 tools/translate/src/config/properties.json create mode 100644 tools/translate/src/config/runtime_variables.json create mode 100644 tools/translate/src/config/spec.json create mode 100644 tools/translate/src/constants.py create mode 100644 tools/translate/src/main.py create mode 100644 unstract/connectors/README.md create mode 100644 unstract/connectors/pyproject.toml create mode 100644 unstract/connectors/src/unstract/connectors/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/base.py create mode 100644 unstract/connectors/src/unstract/connectors/connectorkit.py create mode 100644 unstract/connectors/src/unstract/connectors/constants.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/bigquery/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/bigquery/bigquery.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/bigquery/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/databases/mariadb/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/mariadb/mariadb.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/mariadb/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/databases/mssql/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/mssql/mssql.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/mssql/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/databases/mysql/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/mysql/mysql.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/mysql/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/databases/postgresql/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/postgresql/postgresql.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/postgresql/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/databases/redshift/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/redshift/redshift.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/redshift/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/databases/register.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/snowflake/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/snowflake/snowflake.py create mode 100644 unstract/connectors/src/unstract/connectors/databases/snowflake/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/databases/unstract_db.py create mode 100644 unstract/connectors/src/unstract/connectors/enums.py create mode 100644 unstract/connectors/src/unstract/connectors/exceptions.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/account_services/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/account_services/static/question_answering/apple_10K_2022.pdf create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/box/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/box/box.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/box/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/google_drive/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/google_drive/constants.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/google_drive/google_drive.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/google_drive/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/google_drive/static/settings.yaml create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/http/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/http/http.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/http/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/local_storage/local_storage.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/local_storage/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/minio/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/minio/minio.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/minio/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/register.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/ucs/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/ucs/constants.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/ucs/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/ucs/ucs.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/unstract_file_system.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/zs_dropbox/__init__.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/zs_dropbox/exceptions.py create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/zs_dropbox/static/json_schema.json create mode 100644 unstract/connectors/src/unstract/connectors/filesystems/zs_dropbox/zs_dropbox.py create mode 100644 unstract/connectors/src/unstract/connectors/gcs_helper.py create mode 100644 unstract/connectors/tests/__init__.py create mode 100644 unstract/connectors/tests/databases/test_bigquery_db.py create mode 100644 unstract/connectors/tests/databases/test_mariadb.py create mode 100644 unstract/connectors/tests/databases/test_mssql_db.py create mode 100644 unstract/connectors/tests/databases/test_mysql_db.py create mode 100644 unstract/connectors/tests/databases/test_postgresql_db.py create mode 100644 unstract/connectors/tests/databases/test_redshift_db.py create mode 100644 unstract/connectors/tests/databases/test_snowflake_db.py create mode 100644 unstract/connectors/tests/filesystems/test_box_fs.py create mode 100644 unstract/connectors/tests/filesystems/test_google_drive_fs.py create mode 100644 unstract/connectors/tests/filesystems/test_http_fs.py create mode 100644 unstract/connectors/tests/filesystems/test_miniofs.py create mode 100644 unstract/connectors/tests/filesystems/test_pcs.py create mode 100644 unstract/connectors/tests/filesystems/test_zs_dropbox_fs.py create mode 100644 unstract/connectors/tests/test_connectorkit.py create mode 100644 unstract/core/README.md create mode 100644 unstract/core/pyproject.toml create mode 100644 unstract/core/src/unstract/core/__init__.py create mode 100644 unstract/core/src/unstract/core/llm_helper/__init__.py create mode 100644 unstract/core/src/unstract/core/llm_helper/config.py create mode 100644 unstract/core/src/unstract/core/llm_helper/enums.py create mode 100644 unstract/core/src/unstract/core/llm_helper/llm_cache.py create mode 100644 unstract/core/src/unstract/core/llm_helper/llm_helper.py create mode 100644 unstract/core/src/unstract/core/llm_helper/models.py create mode 100644 unstract/core/src/unstract/core/llm_helper/static/prompts/azure-open-ai/version-0.1/GENERATE_CRON_STRING create mode 100644 unstract/core/src/unstract/core/llm_workflow_generator/__init__.py create mode 100644 unstract/core/src/unstract/core/llm_workflow_generator/dto.py create mode 100644 unstract/core/src/unstract/core/llm_workflow_generator/llm_interface.py create mode 100644 unstract/core/src/unstract/core/llm_workflow_generator/static/prompts/azure-open-ai/version-0.1/prompt create mode 100644 unstract/core/src/unstract/core/pubsub_helper.py create mode 100644 unstract/core/src/unstract/core/utilities.py create mode 100644 unstract/core/tests/account_services/test_pandora_account.py create mode 100644 unstract/core/tests/llm_helper/test_cron_string_gen.py create mode 100644 unstract/core/tests/llm_helper/test_llm_cache.py create mode 100644 unstract/core/tests/test_pubsub_helper.py create mode 100644 unstract/flags/.gitignore create mode 100644 unstract/flags/README.md create mode 100644 unstract/flags/pyproject.toml create mode 100644 unstract/flags/src/unstract/flags/__init__.py create mode 100644 unstract/flags/src/unstract/flags/client.py create mode 100644 unstract/flags/src/unstract/flags/evaluation_pb2.py create mode 100644 unstract/flags/src/unstract/flags/evaluation_pb2_grpc.py create mode 100644 unstract/flags/src/unstract/flags/protos/evaluation.proto create mode 100644 unstract/flags/src/unstract/flags/sample.env create mode 100644 unstract/flags/src/unstract/flags/tests/test_client.py create mode 100644 unstract/flags/tests/__init__.py create mode 100644 unstract/tool-registry/README.md create mode 100644 unstract/tool-registry/pdm.lock create mode 100644 unstract/tool-registry/pyproject.toml create mode 100644 unstract/tool-registry/scripts/load_tools_to_json.py create mode 100644 unstract/tool-registry/src/unstract/tool_registry/__init__.py create mode 100644 unstract/tool-registry/src/unstract/tool_registry/config/sample_registry.yaml create mode 100644 unstract/tool-registry/src/unstract/tool_registry/constants.py create mode 100644 unstract/tool-registry/src/unstract/tool_registry/dto.py create mode 100644 unstract/tool-registry/src/unstract/tool_registry/exceptions.py create mode 100644 unstract/tool-registry/src/unstract/tool_registry/helper.py create mode 100644 unstract/tool-registry/src/unstract/tool_registry/public_tools.json create mode 100644 unstract/tool-registry/src/unstract/tool_registry/schema_validator.py create mode 100644 unstract/tool-registry/src/unstract/tool_registry/tool_registry.py create mode 100644 unstract/tool-registry/src/unstract/tool_registry/tool_utils.py create mode 100644 unstract/tool-registry/tests/test_tool_registry.py create mode 100644 unstract/tool-sandbox/.gitignore create mode 100644 unstract/tool-sandbox/README.md create mode 100644 unstract/tool-sandbox/pyproject.toml create mode 100644 unstract/tool-sandbox/src/unstract/tool_sandbox/__init__.py create mode 100644 unstract/tool-sandbox/src/unstract/tool_sandbox/constants.py create mode 100644 unstract/tool-sandbox/src/unstract/tool_sandbox/helper.py create mode 100644 unstract/tool-sandbox/src/unstract/tool_sandbox/tool_sandbox.py create mode 100644 unstract/workflow-execution/.gitignore create mode 100644 unstract/workflow-execution/README.md create mode 100644 unstract/workflow-execution/pyproject.toml create mode 100644 unstract/workflow-execution/src/unstract/workflow_execution/__init__.py create mode 100644 unstract/workflow-execution/src/unstract/workflow_execution/constants.py create mode 100644 unstract/workflow-execution/src/unstract/workflow_execution/dto.py create mode 100644 unstract/workflow-execution/src/unstract/workflow_execution/enums.py create mode 100644 unstract/workflow-execution/src/unstract/workflow_execution/exceptions.py create mode 100644 unstract/workflow-execution/src/unstract/workflow_execution/execution_file_handler.py create mode 100644 unstract/workflow-execution/src/unstract/workflow_execution/pubsub_helper.py create mode 100644 unstract/workflow-execution/src/unstract/workflow_execution/tools_utils.py create mode 100644 unstract/workflow-execution/src/unstract/workflow_execution/workflow_execution.py create mode 100644 unstract/workflow-execution/tests/sample_instances.json create mode 100644 unstract/workflow-execution/tests/workflow_test.py create mode 100644 worker/.gitignore create mode 100644 worker/README.md create mode 100755 worker/entrypoint.sh create mode 100644 worker/pdm.lock create mode 100644 worker/pyproject.toml create mode 100644 worker/requirements.txt create mode 100644 worker/sample.env create mode 100644 worker/src/unstract/worker/__init__.py create mode 100644 worker/src/unstract/worker/constants.py create mode 100644 worker/src/unstract/worker/main.py create mode 100644 worker/src/unstract/worker/pubsub_helper.py create mode 100644 worker/src/unstract/worker/worker.py create mode 100644 x2text-service/.gitignore create mode 100644 x2text-service/README.md create mode 100644 x2text-service/app/__init__.py create mode 100644 x2text-service/app/authentication_middleware.py create mode 100644 x2text-service/app/config.py create mode 100644 x2text-service/app/controllers/__init__.py create mode 100644 x2text-service/app/controllers/controller.py create mode 100644 x2text-service/app/models.py create mode 100644 x2text-service/app/util.py create mode 100644 x2text-service/pdm.lock create mode 100644 x2text-service/pyproject.toml create mode 100644 x2text-service/run.py create mode 100644 x2text-service/sample.env diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..376557848 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,35 @@ +## What + +... + +## Why + +... + +## How + +... + +## Relevant Docs + +- + +## Related Issues or PRs + +- + +## Dependencies Versions / Env Variables + +- + +## Notes on Testing + +... + +## Screenshots + +... + +## Checklist + +I have read and understood the [Contribution Guidelines](). diff --git a/.github/workflows/ci-container-build.yaml b/.github/workflows/ci-container-build.yaml new file mode 100644 index 000000000..e729ce49a --- /dev/null +++ b/.github/workflows/ci-container-build.yaml @@ -0,0 +1,86 @@ +name: Container Image Build Test for PRs + +env: + VERSION: ci-test # Used for docker tag + +on: + push: + branches: + - main + - development + paths: + - 'backend/**' + - 'frontend/**' + - 'unstract/**' + - 'document-service/**' + - 'platform-service/**' + - 'x2text-service/**' + - 'worker/**' + - 'docker/dockerfiles/**' + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + branches: + - main + - development + paths: + - 'backend/**' + - 'frontend/**' + - 'unstract/**' + - 'document-service/**' + - 'platform-service/**' + - 'x2text-service/**' + - 'worker/**' + - 'docker/dockerfiles/**' + +jobs: + build: + if: github.event.pull_request.draft == false + runs-on: custom-k8s-runner + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Container Build + working-directory: ./docker + run: | + docker compose -f docker-compose.build.yaml build + - name: Container Run + working-directory: ./docker + run: | + cp ../backend/sample.env ../backend/.env + cp ../document-service/sample.env ../document-service/.env + cp ../platform-service/sample.env ../platform-service/.env + cp ../prompt-service/sample.env ../prompt-service/.env + cp ../worker/sample.env ../worker/.env + cp ../x2text-service/sample.env ../x2text-service/.env + cp sample.essentials.env essentials.env + + docker compose -f docker-compose.yaml up -d + sleep 10 + docker compose -f docker-compose.yaml ps -a + # Get the names of exited containers + custom_format="{{.Name}}\t{{.Image}}\t{{.Service}}" + EXITED_CONTAINERS=$(docker compose -f docker-compose.yaml ps -a --filter status=exited --format "$custom_format") + + line_count=$(echo "$EXITED_CONTAINERS" | wc -l) + + if [ "$line_count" -gt 1 ]; then + echo "Exited Containers: $EXITED_CONTAINERS" + + SERVICE=$(echo "$EXITED_CONTAINERS" | awk 'NR>0 {print $3}') + echo "Exited Services:" + echo "$SERVICE" + echo "There are exited containers." + # Print logs of exited containers + IFS=$'\n' + for SERVICE in $SERVICE; do + docker compose -f docker-compose.yaml logs "$SERVICE" + done + docker compose -f docker-compose.yaml down -v + exit 1 + fi + docker compose -f docker-compose.yaml down -v diff --git a/.github/workflows/docker-build-push-dev.yaml b/.github/workflows/docker-build-push-dev.yaml new file mode 100644 index 000000000..7ee93fb44 --- /dev/null +++ b/.github/workflows/docker-build-push-dev.yaml @@ -0,0 +1,64 @@ +name: Unstract Docker Image Build and Push (Development) + +on: + workflow_dispatch: + inputs: + tag: + description: "Docker image tag" + required: true + default: "latest" + service_name: + description: "Service to build" + required: true + default: "backend" # Provide a default value + type: choice + options: # Define available options + - all-services + - frontend + - backend + - document-service + - platform-service + - worker + - prompt-service + - x2text-service + +run-name: "[${{ inputs.service_name }}] Docker Image Build and Push (Development)" + +jobs: + build-and-push: + runs-on: custom-k8s-runner + steps: + - name: Output Inputs + run: echo "${{ toJSON(github.event.inputs) }}" + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + # Build and push Docker image for the specified service + - name: Build and push image for ${{ github.event.inputs.service_name }} + working-directory: ./docker + if: github.event.inputs.service_name != 'all-services' + run: | + VERSION=${{ github.event.inputs.tag }} docker compose -f docker-compose.build.yaml build --no-cache ${{ github.event.inputs.service_name }} + docker push unstract/${{ github.event.inputs.service_name }}:${{ github.event.inputs.tag }} + + # Build and push all service images + - name: Build and push all images + working-directory: ./docker + if: github.event.inputs.service_name == 'all-services' + run: | + VERSION=${{ github.event.inputs.tag }} docker-compose -f docker-compose.build.yaml build --no-cache + # Push all built images + docker push unstract/backend:${{ github.event.inputs.tag }} + docker push unstract/frontend:${{ github.event.inputs.tag }} + docker push unstract/document-service:${{ github.event.inputs.tag }} + docker push unstract/platform-service:${{ github.event.inputs.tag }} + docker push unstract/worker:${{ github.event.inputs.tag }} + docker push unstract/prompt-service:${{ github.event.inputs.tag }} + docker push unstract/x2text-service:${{ github.event.inputs.tag }} diff --git a/.github/workflows/docker-tools-build-push.yaml b/.github/workflows/docker-tools-build-push.yaml new file mode 100644 index 000000000..bc28f4c34 --- /dev/null +++ b/.github/workflows/docker-tools-build-push.yaml @@ -0,0 +1,65 @@ +name: Unstract Tools Docker Image Build and Push (Development) + +on: + workflow_dispatch: + inputs: + tag: + description: "Docker image tag" + required: true + default: "latest" + service_name: + description: "Tool to build" + required: true + default: "tool-classifier" # Provide a default value + type: choice + options: # Define available options + - tool-classifier + - tool-doc-pii-redactor + - tool-indexer + - tool-ocr + - tool-translate + - tool-structure + - tool-text-extractor + +run-name: "[${{ inputs.service_name }}] Docker Image Build and Push (Development)" + +jobs: + build-and-push: + runs-on: custom-k8s-runner + steps: + - name: Output Inputs + run: echo "${{ toJSON(github.event.inputs) }}" + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build tool-classifier + if: github.event.inputs.service_name=='tool-classifier' + run: docker build -t unstract/${{github.event.inputs.service_name}}:${{ github.event.inputs.tag }} ./tools/classifier + - name: Build tool-doc-pii-redactor + if: github.event.inputs.service_name=='tool-doc-pii-redactor' + run: docker build -t unstract/${{github.event.inputs.service_name}}:${{ github.event.inputs.tag }} ./tools/doc_pii_redactor + - name: Build tool-indexer + if: github.event.inputs.service_name=='tool-indexer' + run: docker build -t unstract/${{github.event.inputs.service_name}}:${{ github.event.inputs.tag }} ./tools/indexer + - name: Build tool-ocr + if: github.event.inputs.service_name=='tool-ocr' + run: docker build -t unstract/${{github.event.inputs.service_name}}:${{ github.event.inputs.tag }} ./tools/ocr + - name: Build tool-translate + if: github.event.inputs.service_name=='tool-translate' + run: docker build -t unstract/${{github.event.inputs.service_name}}:${{ github.event.inputs.tag }} ./tools/translate + - name: Build tool-structure + if: github.event.inputs.service_name=='tool-structure' + run: docker build -t unstract/${{github.event.inputs.service_name}}:${{ github.event.inputs.tag }} ./tools/structure + - name: Build tool-text-extractor + if: github.event.inputs.service_name=='tool-text-extractor' + run: docker build -t unstract/${{github.event.inputs.service_name}}:${{ github.event.inputs.tag }} ./tools/text_extractor + + - name: Push Docker image to Docker Hub + run: docker push unstract/${{ github.event.inputs.service_name }}:${{ github.event.inputs.tag }} diff --git a/.github/workflows/production-build.yaml b/.github/workflows/production-build.yaml new file mode 100644 index 000000000..09e163fce --- /dev/null +++ b/.github/workflows/production-build.yaml @@ -0,0 +1,33 @@ +name: Unstract Docker Image Build and Push (Production) + +on: + release: + types: + - created + +run-name: "[${{ github.event.release.tag_name }}] Docker Image Build and Push (Development)" + +jobs: + build-and-push: + runs-on: custom-k8s-runner + strategy: + matrix: + service_name: [backend, frontend, document-service, platform-service, prompt-service, worker, x2text-service] + + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + ref: ${{ github.event.release.tag_name }} + + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push image + working-directory: ./docker + run: | + VERSION=${{ github.event.release.tag_name }} docker-compose -f docker-compose.build.yaml build --no-cache ${{ matrix.service_name }} + docker push unstract/${{ matrix.service_name }}:${{ github.event.release.tag_name }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..9b9ca8f4a --- /dev/null +++ b/.gitignore @@ -0,0 +1,631 @@ +# Created by https://www.toptal.com/developers/gitignore/api/windows,macos,linux,pycharm,pycharm+all,pycharm+iml,python,visualstudiocode,react,django +# Edit at https://www.toptal.com/developers/gitignore?templates=windows,macos,linux,pycharm,pycharm+all,pycharm+iml,python,visualstudiocode,react,django + +### Django ### +*.log +*.pot +*.pyc +__pycache__/ +local_settings.py +media + +# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ +# in your Git repository. Update and uncomment the following line accordingly. +# /staticfiles/ + +### Django.Python Stack ### +# Byte-compiled / optimized / DLL files +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo + +# Django stuff: + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml +.pdm-build +.pdm-python + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.env.export +.venv* +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# 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/ + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### PyCharm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### PyCharm Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml + +### PyCharm+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# AWS User-specific + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# SonarLint plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### PyCharm+all Patch ### +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. + +.idea/* + +!.idea/codeStyles +!.idea/runConfigurations + +### PyCharm+iml ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# AWS User-specific + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# SonarLint plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### PyCharm+iml Patch ### +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +### Python ### +# Byte-compiled / optimized / DLL files + +# C extensions + +# Distribution / packaging + +# 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. + +# Installer logs + +# Unit test / coverage reports + +# Translations + +# Django stuff: + +# Flask stuff: + +# Scrapy stuff: + +# Sphinx documentation + +# PyBuilder + +# Jupyter Notebook + +# IPython + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm + +# Celery stuff + +# SageMath parsed files + +# Environments + +# Spyder project settings + +# Rope project settings + +# mkdocs documentation + +# mypy + +# Pyre type checker + +# pytype static type analyzer + +# Cython debug symbols + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# 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. + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +### react ### +.DS_* +logs +**/*.backup.* +**/*.back.* + +node_modules +bower_components + +*.sublime* + +psd +thumb +sketch + +### VisualStudioCode ### +.vscode/ +**/.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +# !.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Unstract ### + +# Plugins +backend/plugins/authentication/* +!backend/plugins/authentication/auth_sample + +# Tool registry +unstract/tool-registry/src/unstract/tool_registry/*.json +unstract/tool-registry/tests/*.yaml +!unstract/tool-registry/src/unstract/tool_registry/public_tools.json +unstract/tool-registry/src/unstract/tool_registry/config/registry.yaml + +# Docker related +# End of https://www.toptal.com/developers/gitignore/api/windows,macos,linux,pycharm,pycharm+all,pycharm+iml,python,visualstudiocode,react,django +docker/temp/* +docker/init.sql/* +docker/*.env +!docker/sample.*.env +docker/public_tools.json +docker/proxy_overrides.yaml + +# Tool development +tools/*/sdks/ +tools/*/data_dir/ + +docker/workflow_data/ + + diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 000000000..31a0964fe --- /dev/null +++ b/.jshintrc @@ -0,0 +1,3 @@ +{ + "esversion": 9 +} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..56ca20fda --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,200 @@ +--- +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +# - Added unstract feature flag auto generated code to flake8 exclude list +# Force all unspecified python hooks to run python 3.10 +default_language_version: + python: python3.9 +default_stages: + - commit +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: trailing-whitespace + exclude_types: + - "markdown" + - id: end-of-file-fixer + - id: check-yaml + args: [--unsafe] + - id: check-added-large-files + args: ["--maxkb=10240"] + - id: check-case-conflict + - id: check-docstring-first + - id: check-ast + - id: check-json + exclude: ".vscode/launch.json" + - id: check-executables-have-shebangs + - id: check-shebang-scripts-are-executable + - id: check-toml + - id: debug-statements + - id: detect-private-key + - id: check-merge-conflict + - id: check-symlinks + - id: destroyed-symlinks + - id: forbid-new-submodules + - id: mixed-line-ending + - id: no-commit-to-branch + - repo: https://github.com/adrienverge/yamllint + rev: v1.35.1 + hooks: + - id: yamllint + args: ["-d", "relaxed"] + language: system + - repo: https://github.com/rhysd/actionlint + rev: v1.6.26 + hooks: + - id: actionlint-docker + args: [-ignore, 'label ".+" is unknown'] + - repo: https://github.com/psf/black + rev: 24.2.0 + hooks: + - id: black + args: [--config=pyproject.toml, -l 80] + language: system + exclude: | + (?x)^( + unstract/flags/src/unstract/flags/evaluation_.*\.py| + )$ + - repo: https://github.com/pycqa/flake8 + rev: 7.0.0 + hooks: + - id: flake8 + args: [--max-line-length=80] + exclude: | + (?x)^( + .*migrations/.*\.py| + core/tests/.*| + unstract/flags/src/unstract/flags/evaluation_.*\.py| + )$ + - repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort + files: "\\.(py)$" + args: + [ + "--profile", + "black", + "--filter-files", + --settings-path=pyproject.toml, + ] + - repo: https://github.com/hadialqattan/pycln + rev: v2.4.0 + hooks: + - id: pycln + args: [--config=pyproject.toml] + - repo: https://github.com/pycqa/docformatter + rev: v1.7.5 + hooks: + - id: docformatter + # - repo: https://github.com/MarcoGorelli/absolufy-imports + # rev: v0.3.1 + # hooks: + # - id: absolufy-imports + # files: ^backend/ + - repo: https://github.com/asottile/pyupgrade + rev: v3.15.0 + hooks: + - id: pyupgrade + entry: pyupgrade --py39-plus --keep-runtime-typing + types: + - python + - repo: https://github.com/gitleaks/gitleaks + rev: v8.18.2 + hooks: + - id: gitleaks + - repo: https://github.com/hadolint/hadolint + rev: v2.12.1-beta + hooks: + - id: hadolint-docker + args: + - --ignore=DL3003 + - --ignore=DL3008 + - --ignore=DL3013 + - --ignore=DL3018 + - --ignore=SC1091 + files: Dockerfile$ + - repo: https://github.com/asottile/yesqa + rev: v1.5.0 + hooks: + - id: yesqa + - repo: https://github.com/pre-commit/mirrors-eslint + rev: "v9.0.0-beta.0" # Use the sha / tag you want to point at + hooks: + - id: eslint + args: [--config=frontend/.eslintrc.json] + files: \.[jt]sx?$ # *.js, *.jsx, *.ts and *.tsx + types: [file] + additional_dependencies: + - eslint@8.41.0 + - eslint-config-google@0.14.0 + - eslint-config-prettier@8.8.0 + - eslint-plugin-prettier@4.2.1 + - eslint-plugin-react@7.32.2 + - eslint-plugin-import@2.25.2 + - repo: https://github.com/Lucas-C/pre-commit-hooks-nodejs + rev: v1.1.2 + hooks: + - id: htmlhint + - repo: https://github.com/asottile/pyupgrade + rev: v3.15.0 + hooks: + - id: pyupgrade + entry: pyupgrade --py38-plus --keep-runtime-typing + types: + - python + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.8.0 + hooks: + - id: mypy + language: system + entry: mypy . + pass_filenames: false + # IMPORTANT! + # Keep args same as tool.mypy section in pyproject.toml + args: + [ + --allow-subclassing-any, + --allow-untyped-decorators, + --check-untyped-defs, + --exclude, ".*migrations/.*.py", + --exclude, "backend/prompt/.*", + --exclude, "document-service/.*", + --exclude, "unstract/connectors/tests/.*", + --exclude, "unstract/core/.*", + --exclude, "unstract/flags/src/unstract/flags/.*", + --exclude, "__pypackages__/.*", + --follow-imports, "silent", + --ignore-missing-imports, + --implicit-reexport, + --pretty, + --python-version=3.9, + --show-column-numbers, + --show-error-codes, + --strict, + --warn-redundant-casts, + --warn-return-any, + --warn-unreachable, + --warn-unused-configs, + --warn-unused-ignores, + ] + - repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.39.0 + hooks: + - id: markdownlint + args: [--disable, MD013] + - id: markdownlint-fix + args: [--disable, MD013] + - repo: https://github.com/pdm-project/pdm + rev: 2.12.3 + hooks: + - id: pdm-lock-check + - repo: local + hooks: + - id: check-django-migrations + name: Check django migrations + entry: sh -c 'pdm run `find . -name "manage.py" -not -path "*/.venv/*"` makemigrations --check --dry-run --no-input' + language: system + types: [python] # hook only runs if a python file is staged + pass_filenames: false diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md new file mode 100644 index 000000000..fdb59770d --- /dev/null +++ b/CONTRIBUTE.md @@ -0,0 +1,3 @@ +Conventions + +- Where ever you are adding yaml files, preferred extension is `.yaml` diff --git a/README.md b/README.md new file mode 100644 index 000000000..509c369e2 --- /dev/null +++ b/README.md @@ -0,0 +1,199 @@ +# Unstract + +[![pdm-managed](https://img.shields.io/badge/pdm-managed-blueviolet)](https://pdm-project.org) + +TODO: Write few lines about the project. + +## System Requirements + +- docker +- git + +## Running with docker compose + +- All services needed by the backend can be run with + +``` +cd docker/ +VERSION=test docker compose -f docker-compose.build.yaml build +VERSION=test docker compose -f docker-compose.yaml up -d +``` + +Additional information on running with Docker can be found in [DOCKERISING.md](/DOCKERISING.md) + +- Use the `-f` flag to run all dependencies necessary for development, this runs containers needed for testing as well such as Minio. + +``` +docker compose -f docker-compose-dev-essentials.yaml up +``` + +- It might take sometime on the first run to pull the images. + +## Running locally + +### Installation + +- Install the below libraries which are needed to run Unstract + - Linux + + ``` + sudo apt install build-essential pkg-config libpoppler-cpp-dev libmagic-dev python3-dev + ``` + + - Mac + + ``` + brew install pkg-config poppler freetds libmagic + ``` + +### Create your virtual env + +- In order to install dependencies and run a package, ensure that you've sourced a virtual environment within that package. All commands in this repository assumes that you have sourced your required venv. + +``` +cd +python -m venv .venv +source ./venv/bin/activate +``` + + +### Install dependencies with PDM + +- This repository makes use of [PDM](https://github.com/pdm-project/pdm) for managing dependencies with the help of a virtual +environment. +- If you haven't installed PDM in your machine yet, + - Install it using the below command + ``` + curl -sSL https://pdm.fming.dev/install-pdm.py | python3 - + ``` + - Or install it from PyPI using `pip` + ``` + pip install pdm + ``` + +Ensure you're running the PDM commands from the corresponding package root +- Install dependencies for running the package with + +``` +pdm install +``` +This install dev dependencies as well by default +- For production, install the requirements with + +``` +pdm install --prod +``` + +- With PDM its possible to run some services from any directory within this +repository. To list the possible scripts that can be executed +``` +pdm run -l +``` + +- Add a new dependency with (ensure you're running it from the correct project's root) +Perform an editable install with `-e` only for local development. +``` +pdm add +pdm add -e +``` +- List all dependencies with +``` +pdm list +``` +- After updating `pyproject.toml`s with a newly added dependency, the lock file can be updated with +``` +pdm lock +``` +- Refer [PDM's documentation](https://pdm.fming.dev/latest/reference/cli/) for further details. + +### Configuring Postgres + +- Create a Postgres user and DB for the BE and configure it like so + +``` +POSTGRES_USER: unstract_dev +POSTGRES_PASSWORD: unstract_pass +POSTGRES_DB: unstract_db +``` + +If you require a different config, make sure the necessary envs from [backend/sample.env](/backend/sample.env) are exported. + +- Execute the script [backend/init.sql](/backend/init.sql) that adds roles and creates a DB and extension for ZS Document Indexer tool to work. +Make sure that [pgvector](https://github.com/pgvector/pgvector#installation) is installed. + +### Pre-commit hooks + +- We use pre-commit to run some hooks whenever code is pushed to perform linting and static code analysis among other checks. +- Ensure dev dependencies are installed and you're in the virtual env +- Install hooks with `pre-commit install` or `pdm run pre-commit install` +- Manually trigger pre-commit hooks in following ways: + ```bash + # + # Using the tool directly + # + # Run all pre-commit hooks + pre-commit run + # Run specific pre-commit hook + pre-commit run flake8 + # Run mypy pre-commit hook for selected folder + pre-commit run mypy --files prompt-service/**/*.py + # Run mypy for selected folder + mypy prompt-service/**/*.py + + # + # Using pdm to run the scripts + # + # Run all pre-commit hooks + pdm run pre-commit run + # Run specific pre-commit hook + pdm run pre-commit run flake8 + # Run mypy pre-commit hook for selected folder + pdm run pre-commit run mypy --files prompt-service/**/*.py + # Run mypy for selected folder + pdm run mypy prompt-service/**/*.py + ``` + +### Backend + +- Check [backend/README.md](/backend/README.md) for running the backend. + +### Frontend + +- Install dependencies with `npm install` +- Start the server with `npm start` + +### Traefik Proxy Overrides + +It is possible to simultaneously run few services directly on docker host while others are run as docker containers via docker compose. +This enables seamless development without worrying about deployment of other services which you are not concerned with. + +We just need to override default Traefik proxy routing to allow this, that's all. + +1. Copy `docker/sample.proxy_overrides.yaml` to `docker/proxy_overrides.yaml`. + Modify to update Traefik proxy routes for services running directly on docker host (`host.docker.internal:`). + +2. Update host name of dependency components in config of services running directly on docker host: + - Replace as `*.localhost` IF container port is exposed on docker host + - **OR** use container IPs obtained via `docker network inspect unstract-network` + - **OR** run `dockers/scripts/resolve_container_svc_from_host.sh` IF container port is NOT exposed on docker host or if you want to keep dependency host names unchanged + +Run the services. + +#### Conflicting Host Names + +When same host name environment variables are used by both the service running locally and a service +running in a container (for example, running in from a tool), host name resolution conflicts can arise for the following: + +- `localhost` -> Using this inside a container points to the container itself, and not the host. +- `host.docker.internal` -> Meant to be used inside containers only, to get host IP. +Does not make sense to use in services running locally. + +*In such cases, use another host name and point the same to host IP in `/etc/hosts`.* + +For example, the backend uses the PROMPT_HOST environment variable, which is also supplied +in the Tool configuration when spawning Tool containers. If the backend is running +locally and the Tools are in containers, we could set the value to +`prompt-service` and add it to `/etc/hosts` as shown below. +``` + prompt-service +``` diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 000000000..aee7d5613 --- /dev/null +++ b/backend/README.md @@ -0,0 +1,136 @@ +# Unstract Backend + +Contains the backend services for Unstract written with Django and DRF. + +## Dependencies + +1. Postgres +1. Redis + +## Getting started +**NOTE**: All commands are executed from `/backend` and require the venv to be active. Refer [these steps](/README.md#create-your-virtual-env) to create/activate your venv + +### Install and run manually + +- Ensure that you've sourced your virtual environment and installed dependencies mentioned [here](/README.md#create-your-virtual-env). + +- If you plan to run the django server locally, make sure the dependent services are up (either locally or through docker compose) +- Copy `sample.env` into `.env` and update the necessary variables. For eg: + +``` +DJANGO_SETTINGS_MODULE='backend.settings.dev' +DB_HOST='localhost' +DB_USER='unstract_dev' +DB_PASSWORD='unstract_pass' +DB_NAME='unstract_db' +DB_PORT=5432 +``` + +- If you've made changes to the model, run `python manage.py makemigrations`, else ignore this step +- Run the following to apply any migrations to the DB and start the server + +``` +python manage.py migrate +python manage.py runserver localhost:8000 +``` + +- Server will start and run at port 8000. () + +## Asynchronous execution/pipeline execution + + - Working with celery + - Each pipeline or shared tasks will added to the queue (Redis), And the worker will consume from the queue + +### Run Execution Worker + +Run the following command to start the worker: + +```bash +celery -A backend worker --loglevel=info +``` + +### Worker Dashboard + +- We have to ensure the package flower is installed in the current environment +- Run command + +```bash +celery -A backend flower +``` +This command will start Flower on the default port (5555) and can be accessed via a web browser. Flower provides a user-friendly interface for monitoring and managing Celery tasks + + +## Connecting to Postgres + +Follow the below steps to connect to the postgres DB running with `docker compose`. + +1. Exec into a shell within the postgres container + +``` +docker compose exec -it db bash +``` + +2. Connect to the db as the specified user + +``` +psql -d unstract_db -U unstract_dev +``` + +3. Execute PSQL commands within the shell. + +## API Docs + +While running the backend server locally, access the API documentation that's auto generated at +the backend endpoint `/api/v1/doc/`. + +**NOTE:** There exists issues accessing this when the django server is run with gunicorn (in case of running with +a container) + +- [Account](account/api_doc.md) +- [FileManagement](file_management/api_doc.md) + +## Connectors + +### Google Drive +The Google Drive connector makes use of [PyDrive2](https://pypi.org/project/PyDrive2/) library and supports only OAuth 2.0 authentication. +To set it up, follow the first step higlighted in [Google's docs](https://developers.google.com/identity/protocols/oauth2#1.-obtain-oauth-2.0-credentials-from-the-dynamic_data.setvar.console_name-.) and set the client ID and client secret +as envs in `backend/.env` +``` +GOOGLE_OAUTH2_KEY="" +GOOGLE_OAUTH2_SECRET="" +``` + + +# Archived - (EXPERIMENTAL) + +## Accessing the admin site + +- If its the first time, create a super user and follow the on-screen instructions + +``` +python manage.py createsuperuser +``` + +- Register your models in `/admin.py`, for example + +``` +from django.contrib import admin +from .models import Prompt + +admin.site.register(Prompt) +``` + +- Make sure the server is running and hit the `/admin` endpoint + +## Running unit tests + +Units tests are run with [pytest](https://docs.pytest.org/en/7.3.x/) and [pytest-django](https://pytest-django.readthedocs.io/en/latest/index.html) + +``` +pytest +pytest prompt # To run for an app named prompt +``` + +All tests are organized within an app, for eg: `prompt/tests/test_urls.py` + +**NOTE:** The django server need not be up to run the tests, however the DB needs to be running. diff --git a/backend/account/ReadMe.md b/backend/account/ReadMe.md new file mode 100644 index 000000000..35695cfb5 --- /dev/null +++ b/backend/account/ReadMe.md @@ -0,0 +1,26 @@ +# Basic WorkFlow + +`We can Add Workflows Here` + +## Login + +### Step + +1. Login +2. Get Organizations +3. Set Organization +4. Use organizational APIs /unstract// + +## Switch organization + +1. Get Organizations +2. Set Organization +3. Use organizational APIs /unstract// + +## Get current user and Organization data + +- Use Get User Profile and Get Organization Info APIs + +## Signout + +1.signout APi diff --git a/backend/account/__init__.py b/backend/account/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/account/admin.py b/backend/account/admin.py new file mode 100644 index 000000000..6eab2ecfa --- /dev/null +++ b/backend/account/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import Organization, User + +admin.site.register([Organization, User]) \ No newline at end of file diff --git a/backend/account/api_doc.md b/backend/account/api_doc.md new file mode 100644 index 000000000..d77e326c6 --- /dev/null +++ b/backend/account/api_doc.md @@ -0,0 +1,202 @@ +# Authentication APIs + +### Unauthorized Attempt + +**Status Code:** 401 + +**Response:** + +```json +{ + "message": "Unauthorized" +} +``` + +### Login + +```http +GET /login +``` + +Sample URL: +> /login + +Response: Auth0 login page + +### Logout + +```http +GET /logout +``` + +Sample URL: +> /logout + +Response: OK (redirect to Auth0 page) + +### Signup + +```http +GET /signup +``` + +Sample URL: +> /signup + +Response: Auth0 signup page + +### Get User Profile + +```http +GET /profile +``` + +Sample URL: +> /unstract//profile + +Response: + +```json +{ + "user": { + "id": "6", + "email": "iamali003@gmail.com", + "name": "Ali", + "display_name": "Ali", + "family_name": null, + "picture": null + } +} +``` + +### Password Reset + +```http +POST /reset_password +``` + +Sample URL: +> /unstract//reset_password + +Response: + +```json +{ + "status": "failed", + "message": "user doesn't have Username-Password-Authentication" +} +``` + +### Get Organizations of User + +```http +GET /organization +``` + +Sample URL: +> /organization + +Response: + +```json +{ + "message": "success", + "organizations": [ + { + "id": "org_Z12elHhCcPH5rPD7", + "display_name": "Personal Org", + "name": "personal" + }, + { + "id": "org_CB46CBskR8BxFjVV", + "display_name": "ali Test", + "name": "ali1" + } + ] +} +``` + +### Select an Organization to Use + +```http +POST /set +``` + +Sample URL: +> /organization//set + +Response: + +```json +{ + "user": { + "id": "6", + "email": "iamali003@gmail.com", + "name": "Ali", + "display_name": "Ali", + "family_name": null, + "picture": null + }, + "organization": { + "display_name": "ali Test", + "name": "ali1", + "organization_id": "org_CB46CBskR8BxFjVV" + } +} + +``` + +### Get Organization Members + +```http +GET /members +``` + +Sample URL: +> /unstract//members + +Response: + +```json +{ + "message": "success", + "members": [ + { + "user_id": "google-oauth2|102763382532901780910", + "email": "iamali003@gmail.com", + "name": "", + "picture": null + } + ] +} +``` + +### Get Organization Info + +```http +GET /organization +``` + +Sample URL: +> /unstract//organization + +Response: + +```json +{ + "message": "success", + "organization": { + "name": "ali1", + "display_name": "ali Test", + "organization_id": "org_CB46CBskR8BxFjVV", + "created_at": "2023-06-26 04:42:40.905458+00:00" + } +} +``` + +## Ref + +- Postman Collection : [postaman collection link](https://api.postman.com/collections/24537488-9380ea92-d1e0-45f4-827c-c5cc9d0370b8?access_key=PMAT-01H3VGHTM9SR01MHXA95G1RTWB) +- By testing Postman + - set cookies + - set X-CSRFToken in header for POST request diff --git a/backend/account/apps.py b/backend/account/apps.py new file mode 100644 index 000000000..2c684a9eb --- /dev/null +++ b/backend/account/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AccountConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "account" diff --git a/backend/account/authentication_controller.py b/backend/account/authentication_controller.py new file mode 100644 index 000000000..1fa40f998 --- /dev/null +++ b/backend/account/authentication_controller.py @@ -0,0 +1,508 @@ +import logging +from typing import Any, Optional, Union +from urllib.parse import urlencode + +from account.authentication_helper import AuthenticationHelper +from account.authentication_plugin_registry import AuthenticationPluginRegistry +from account.authentication_service import AuthenticationService +from account.cache_service import CacheService +from account.constants import ( + AuthoErrorCode, + Cookie, + ErrorMessage, + OrganizationMemberModel, +) +from account.custom_exceptions import ( + DuplicateData, + Forbidden, + UserNotExistError, +) +from account.dto import ( + CallbackData, + MemberInvitation, + OrganizationData, + UserInfo, + UserInviteResponse, + UserRoleData, +) +from account.exceptions import OrganizationNotExist +from account.models import Organization, User +from account.organization import OrganizationService +from account.serializer import ( + GetOrganizationsResponseSerializer, + OrganizationSerializer, + SetOrganizationsResponseSerializer, +) +from account.user import UserService +from django.conf import settings +from django.contrib.auth import login as django_login +from django.contrib.auth import logout as django_logout +from django.db.utils import IntegrityError +from django.middleware import csrf +from django.shortcuts import redirect +from django_tenants.utils import tenant_context +from psycopg2.errors import UndefinedTable +from rest_framework import status +from rest_framework.request import Request +from rest_framework.response import Response +from tenant_account.models import OrganizationMember as OrganizationMember +from tenant_account.organization_member_service import OrganizationMemberService + +Logger = logging.getLogger(__name__) + + +class AuthenticationController: + """Authentication Controller This controller class manages user + authentication processes.""" + + def __init__(self) -> None: + """This method initializes the controller by selecting the appropriate + authentication plugin based on availability.""" + self.authentication_helper = AuthenticationHelper() + self.organization_member_service = OrganizationMemberService() + if AuthenticationPluginRegistry.is_plugin_available(): + self.auth_service: AuthenticationService = ( + AuthenticationPluginRegistry.get_plugin() + ) + else: + self.auth_service = AuthenticationService() + + def user_login( + self, + request: Request, + ) -> Any: + return self.auth_service.user_login(request) + + def user_signup(self, request: Request) -> Any: + return self.auth_service.user_signup(request) + + def authorization_callback( + self, request: Request, backend: str = settings.DEFAULT_MODEL_BACKEND + ) -> Any: + """Handle authorization callback. + + This function processes the authorization callback from + an external service. + + Args: + request (Request): Request instance + backend (str, optional): backend used to use login. + Defaults: settings.DEFAULT_MODEL_BACKEND. + + Returns: + Any: Redirect response + """ + + callback_data: CallbackData = self.auth_service.get_callback_data( + request=request + ) + user: User = self.get_or_create_user_by_email(request, callback_data) + try: + member = self.auth_service.handle_invited_user_while_callback( + request=request, user=user + ) + + except Exception as ex: + """Error code reference + frontend/src/components/error/GenericError/GenericError.jsx.""" + if ex.code == AuthoErrorCode.IDM: # type: ignore + query_params = {"code": AuthoErrorCode.IDM} + return redirect( + f"{settings.ERROR_URL}?{urlencode(query_params)}" + ) + elif ex.code == AuthoErrorCode.UMM: # type: ignore + query_params = {"code": AuthoErrorCode.UMM} + return redirect( + f"{settings.ERROR_URL}?{urlencode(query_params)}" + ) + + return redirect(f"{settings.ERROR_URL}") + + if member.organization_id and member.role and len(member.role) > 0: + organization: Optional[Organization] = ( + OrganizationService.get_organization_by_org_id( + member.organization_id + ) + ) + if organization: + try: + self.create_tenant_user( + organization=organization, user=user + ) + except UndefinedTable: + pass + + response = self.auth_service.handle_authorization_callback( + user=user, + data=callback_data, + redirect_url=request.GET.get("redirect_url"), + ) + django_login(request, user, backend) + + return response + + def user_organizations(self, request: Request) -> Any: + """List a user's organizations. + + Args: + user (User): User instance + z_code (str): _description_ + + Returns: + list[OrganizationData]: _description_ + """ + + try: + organizations = self.auth_service.user_organizations(request) + except Exception as ex: + # + self.user_logout(request) + if ex.code == AuthoErrorCode.USF: # type: ignore + response = Response( + status=status.HTTP_412_PRECONDITION_FAILED, + data={"domain": ex.data.get("domain")}, # type: ignore + ) + return response + user: User = request.user + org_ids = {org.id for org in organizations} + CacheService.set_user_organizations(user.user_id, list(org_ids)) + + serialized_organizations = GetOrganizationsResponseSerializer( + organizations, many=True + ).data + response = Response( + status=status.HTTP_200_OK, + data={ + "message": "success", + "organizations": serialized_organizations, + }, + ) + if Cookie.CSRFTOKEN not in request.COOKIES: + csrf_token = csrf.get_token(request) + response.set_cookie(Cookie.CSRFTOKEN, csrf_token) + + return response + + def set_user_organization( + self, request: Request, organization_id: str + ) -> Response: + user: User = request.user + organization_ids = CacheService.get_user_organizations(user.user_id) + if not organization_ids: + z_organizations: list[OrganizationData] = ( + self.auth_service.get_organizations_by_user_id(user.user_id) + ) + organization_ids = {org.id for org in z_organizations} + if organization_id and organization_id in organization_ids: + organization = OrganizationService.get_organization_by_org_id( + organization_id + ) + if not organization: + try: + organization_data: OrganizationData = ( + self.auth_service.get_organization_by_org_id( + organization_id + ) + ) + except ValueError: + raise OrganizationNotExist() + try: + organization = OrganizationService.create_organization( + organization_data.name, + organization_data.display_name, + organization_data.id, + ) + except IntegrityError: + raise DuplicateData( + f"{ErrorMessage.ORGANIZATION_EXIST}, \ + {ErrorMessage.DUPLICATE_API}" + ) + self.create_tenant_user(organization=organization, user=user) + user_info: Optional[UserInfo] = self.get_user_info(request) + serialized_user_info = SetOrganizationsResponseSerializer( + user_info + ).data + organization_info = OrganizationSerializer(organization).data + response: Response = Response( + status=status.HTTP_200_OK, + data={ + "user": serialized_user_info, + "organization": organization_info, + }, + ) + # Update user session data in redis + user_session_info: dict[str, Any] = ( + CacheService.get_user_session_info(user.email) + ) + user_session_info["current_org"] = organization_id + CacheService.set_user_session_info(user_session_info) + response.set_cookie(Cookie.ORG_ID, organization_id) + return response + return Response(status=status.HTTP_403_FORBIDDEN) + + def get_user_info(self, request: Request) -> Optional[UserInfo]: + return self.auth_service.get_user_info(request) + + def is_admin_by_role(self, role: str) -> bool: + """Check the role is act as admin in the context of authentication + plugin. + + Args: + role (str): role + + Returns: + bool: _description_ + """ + return self.auth_service.is_admin_by_role(role=role) + + def get_organization_info(self, org_id: str) -> Optional[Organization]: + organization = self.auth_service.get_organization_info(org_id) + if not organization: + organization = OrganizationService.get_organization_by_org_id( + org_id=org_id + ) + return organization + + def make_organization_and_add_member( + self, + user_id: str, + user_name: str, + organization_name: Optional[str] = None, + display_name: Optional[str] = None, + ) -> Optional[OrganizationData]: + return self.auth_service.make_organization_and_add_member( + user_id, user_name, organization_name, display_name + ) + + def make_user_organization_name(self) -> str: + return self.auth_service.make_user_organization_name() + + def make_user_organization_display_name(self, user_name: str) -> str: + return self.auth_service.make_user_organization_display_name(user_name) + + def user_logout(self, request: Request) -> Response: + response = self.auth_service.user_logout(request=request) + django_logout(request) + return response + + def get_organization_members_by_org_id( + self, organization_id: Optional[str] = None + ) -> list[OrganizationMember]: + members: list[OrganizationMember] = OrganizationMember.objects.all() + return members + + def get_organization_members_by_user( + self, user: User + ) -> OrganizationMember: + member: OrganizationMember = OrganizationMember.objects.filter( + user=user + ).first() + return member + + def get_user_roles(self) -> list[UserRoleData]: + return self.auth_service.get_roles() + + def get_user_invitations( + self, organization_id: str + ) -> list[MemberInvitation]: + return self.auth_service.get_invitations( + organization_id=organization_id + ) + + def delete_user_invitation( + self, organization_id: str, invitation_id: str + ) -> bool: + return self.auth_service.delete_invitation( + organization_id=organization_id, invitation_id=invitation_id + ) + + def reset_user_password(self, user: User) -> Response: + return self.auth_service.reset_user_password(user) + + def invite_user( + self, + admin: User, + org_id: str, + user_list: list[dict[str, Union[str, None]]], + ) -> list[UserInviteResponse]: + """Invites users to join an organization. + + Args: + admin (User): Admin user initiating the invitation. + org_id (str): ID of the organization to which users are invited. + user_list (list[dict[str, Union[str, None]]]): + List of user details for invitation. + Returns: + list[UserInviteResponse]: List of responses for each + user invitation. + """ + admin_user = OrganizationMember.objects.get(user=admin.id) + if not self.auth_service.is_organization_admin(admin_user): + raise Forbidden() + response = [] + for user_item in user_list: + email = user_item.get("email") + role = user_item.get("role") + if email: + user = self.organization_member_service.get_user_by_email( + email=email + ) + user_response = {} + user_response["email"] = email + message: str = "User invitation successful" + if user: + # Already in organization + status = False + message = "User is already part of current organization." + else: + try: + self.auth_service.check_user_organization_association( + user_email=email + ) + status = self.auth_service.invite_user( + admin_user, org_id, email, role=role + ) + except Exception as exception: + status = False + message = exception.message # type: ignore + response.append( + UserInviteResponse( + email=email, + status="success" if status else "failed", + message=message, + ) + ) + return response + + def remove_users_from_organization( + self, admin: User, organization_id: str, user_emails: list[str] + ) -> bool: + admin_user = OrganizationMember.objects.get(user=admin.id) + user_ids = OrganizationMember.objects.filter( + user__email__in=user_emails + ).values_list( + OrganizationMemberModel.USER_ID, OrganizationMemberModel.ID + ) + user_ids_list: list[str] = [] + ids_list: list[str] = [] + for user in user_ids: + user_ids_list.append(user[0]) + ids_list.append(user[1]) + if len(user_ids_list) > 0: + is_removed = self.auth_service.remove_users_from_organization( + admin=admin_user, + organization_id=organization_id, + user_ids=user_ids_list, + ) + else: + is_removed = False + if is_removed: + OrganizationMember.objects.filter(user__in=ids_list).delete() + return is_removed + + def add_user_role( + self, admin: User, org_id: str, email: str, role: str + ) -> Optional[str]: + admin_user = OrganizationMember.objects.get(user=admin.id) + user = self.organization_member_service.get_user_by_email(email=email) + if user: + current_roles = self.auth_service.add_organization_user_role( + admin_user, org_id, user.user.user_id, [role] + ) + if current_roles: + self.save_orgnanization_user_role( + user_id=user.user.user_id, role=current_roles[0] + ) + return current_roles[0] + else: + return None + + def remove_user_role( + self, admin: User, org_id: str, email: str, role: str + ) -> Optional[str]: + admin_user = OrganizationMember.objects.get(user=admin.id) + organization_member = ( + self.organization_member_service.get_user_by_email(email=email) + ) + if organization_member: + current_roles = self.auth_service.remove_organization_user_role( + admin_user, org_id, organization_member.user.user_id, [role] + ) + if current_roles: + self.save_orgnanization_user_role( + user_id=organization_member.user.user_id, + role=current_roles[0], + ) + return current_roles[0] + else: + return None + + def save_orgnanization_user_role(self, user_id: str, role: str) -> None: + organization_user = ( + self.organization_member_service.get_user_by_user_id( + user_id=user_id + ) + ) + if organization_user: + # consider single role + organization_user.role = role + organization_user.save() + + def create_tenant_user( + self, organization: Organization, user: User + ) -> None: + with tenant_context(organization): + existing_tenant_user = ( + self.organization_member_service.get_user_by_id(id=user.id) + ) + if existing_tenant_user: + Logger.info(f"{existing_tenant_user.user.email} Already exist") + else: + account_user = self.get_or_create_user(user=user) + if account_user: + user_roles = ( + self.auth_service.get_organization_role_of_user( + user_id=account_user.user_id, + organization_id=organization.organization_id, + ) + ) + user_role = user_roles[0] + tenant_user: OrganizationMember = OrganizationMember( + user=user, role=user_role + ) + tenant_user.save() + else: + raise UserNotExistError() + + def get_or_create_user_by_email( + self, request: Request, callback_data: CallbackData + ) -> Union[User, OrganizationMember]: + email = callback_data.email + user_service = UserService() + user = user_service.get_user_by_email(email) + if not user: + user_id = callback_data.user_id + user = user_service.create_user(email, user_id) + return user + + def get_or_create_user( + self, user: User + ) -> Optional[Union[User, OrganizationMember]]: + user_service = UserService() + if user.id: + account_user: Optional[User] = user_service.get_user_by_id(user.id) + if account_user: + return account_user + elif user.email: + account_user = user_service.get_user_by_email(email=user.email) + if account_user: + return account_user + if user.user_id: + user.save() + return user + elif user.email and user.user_id: + account_user = user_service.create_user( + email=user.email, user_id=user.user_id + ) + return account_user + return None diff --git a/backend/account/authentication_helper.py b/backend/account/authentication_helper.py new file mode 100644 index 000000000..69a80dcd4 --- /dev/null +++ b/backend/account/authentication_helper.py @@ -0,0 +1,38 @@ +from typing import Any + +from account.constants import DefaultOrg +from account.dto import CallbackData, MemberData, OrganizationData +from rest_framework.request import Request + + +class AuthenticationHelper: + def __init__(self) -> None: + pass + + def get_organizations_by_user_id(self) -> list[OrganizationData]: + organizationData: OrganizationData = OrganizationData( + id=DefaultOrg.MOCK_ORG, + display_name=DefaultOrg.MOCK_ORG, + name=DefaultOrg.MOCK_ORG, + ) + return [organizationData] + + def get_authorize_token(rself, equest: Request) -> CallbackData: + return CallbackData( + user_id=DefaultOrg.MOCK_USER_ID, + email=DefaultOrg.MOCK_USER_EMAIL, + token="", + ) + + def list_of_members_from_user_model( + self, model_data: list[Any] + ) -> list[MemberData]: + members: list[MemberData] = [] + for data in model_data: + user_id = data.user_id + email = data.email + name = data.username + + members.append(MemberData(user_id=user_id, email=email, name=name)) + + return members diff --git a/backend/account/authentication_plugin_registry.py b/backend/account/authentication_plugin_registry.py new file mode 100644 index 000000000..9503b108d --- /dev/null +++ b/backend/account/authentication_plugin_registry.py @@ -0,0 +1,98 @@ +import logging +import os +from importlib import import_module +from typing import Any + +from account.constants import PluginConfig +from django.apps import apps + +Logger = logging.getLogger(__name__) + + +def _load_plugins() -> dict[str, dict[str, Any]]: + """Iterating through the Authentication plugins and register their + metadata.""" + auth_app = apps.get_app_config(PluginConfig.PLUGINS_APP) + auth_package_path = auth_app.module.__package__ + auth_dir = os.path.join(auth_app.path, PluginConfig.AUTH_PLUGIN_DIR) + auth_package_path = f"{auth_package_path}.{PluginConfig.AUTH_PLUGIN_DIR}" + auth_modules = {} + + for item in os.listdir(auth_dir): + # Loads a plugin only if name starts with `auth`. + if not item.startswith(PluginConfig.AUTH_MODULE_PREFIX): + continue + # Loads a plugin if it is in a directory. + if os.path.isdir(os.path.join(auth_dir, item)): + auth_module_name = item + # Loads a plugin if it is a shared library. + # Module name is extracted from shared library name. + # `auth.platform_architecture.so` will be file name and + # `auth` will be the module name. + elif item.endswith(".so"): + auth_module_name = item.split(".")[0] + else: + continue + try: + full_module_path = f"{auth_package_path}.{auth_module_name}" + module = import_module(full_module_path) + metadata = getattr(module, PluginConfig.AUTH_METADATA, {}) + if metadata.get(PluginConfig.METADATA_IS_ACTIVE, False): + auth_modules[auth_module_name] = { + PluginConfig.AUTH_MODULE: module, + PluginConfig.AUTH_METADATA: module.metadata, + } + Logger.info( + "Loaded auth plugin: %s, is_active: %s", + module.metadata["name"], + module.metadata["is_active"], + ) + else: + Logger.warning( + "Metadata is not active for %s authentication module.", + auth_module_name, + ) + except ModuleNotFoundError as exception: + Logger.error( + "Error while importing authentication module : %s", + exception, + ) + + if len(auth_modules) > 1: + raise ValueError( + "Multiple authentication modules found." + "Only one authentication method is allowed." + ) + elif len(auth_modules) == 0: + Logger.warning( + "No authentication modules found." + "Application will start without authentication module" + ) + return auth_modules + + +class AuthenticationPluginRegistry: + auth_modules: dict[str, dict[str, Any]] = _load_plugins() + + @classmethod + def is_plugin_available(cls) -> bool: + """Check if any authentication plugin is available. + + Returns: + bool: True if a plugin is available, False otherwise. + """ + return len(cls.auth_modules) > 0 + + @classmethod + def get_plugin(cls) -> Any: + """Get the selected authentication plugin. + + Returns: + AuthenticationService: Selected authentication plugin instance. + """ + chosen_auth_module = next(iter(cls.auth_modules.values())) + chosen_metadata = chosen_auth_module[PluginConfig.AUTH_METADATA] + service_class_name = chosen_metadata[ + PluginConfig.METADATA_SERVICE_CLASS + ] + return service_class_name() diff --git a/backend/account/authentication_service.py b/backend/account/authentication_service.py new file mode 100644 index 000000000..6056d21da --- /dev/null +++ b/backend/account/authentication_service.py @@ -0,0 +1,326 @@ +import logging +import uuid +from typing import Any, Optional + +from account.authentication_helper import AuthenticationHelper +from account.cache_service import CacheService +from account.constants import Common, DefaultOrg +from account.custom_exceptions import Forbidden, MethodNotImplemented +from account.dto import ( + CallbackData, + MemberData, + MemberInvitation, + OrganizationData, + ResetUserPasswordDto, + UserInfo, + UserRoleData, + UserSessionInfo, +) +from account.enums import UserRole +from account.models import Organization, User +from account.organization import OrganizationService +from django.http import HttpRequest +from rest_framework.request import Request +from rest_framework.response import Response +from tenant_account.models import OrganizationMember as OrganizationMember + +Logger = logging.getLogger(__name__) + + +class AuthenticationService: + def __init__(self) -> None: + self.authentication_helper = AuthenticationHelper() + self.default_user: User = self.get_user() + self.default_organization: Organization = self.user_organization() + self.user_session_info = self.get_user_session_info() + + def get_current_organization(self) -> Organization: + return self.default_organization + + def get_current_user(self) -> User: + return self.default_user + + def get_current_user_session(self) -> UserSessionInfo: + return self.user_session_info + + def user_login(self, request: HttpRequest) -> Any: + raise MethodNotImplemented() + + def user_signup(self, request: HttpRequest) -> Any: + raise MethodNotImplemented() + + def is_admin_by_role(self, role: str) -> bool: + """Check the role with actual admin Role. + + Args: + role (str): input string + + Returns: + bool: _description_ + """ + try: + return UserRole(role.lower()) == UserRole.ADMIN + except ValueError: + return False + + def get_callback_data(self, request: Request) -> CallbackData: + return CallbackData( + user_id=DefaultOrg.MOCK_USER_ID, + email=DefaultOrg.MOCK_USER_EMAIL, + token="", + ) + + def user_organization(self) -> Organization: + return Organization( + name=DefaultOrg.ORGANIZATION_NAME, + display_name=DefaultOrg.ORGANIZATION_NAME, + organization_id=DefaultOrg.ORGANIZATION_NAME, + schema_name=DefaultOrg.ORGANIZATION_NAME, + ) + + def handle_invited_user_while_callback( + self, request: Request, user: User + ) -> MemberData: + member_data: MemberData = MemberData( + user_id=self.default_user.user_id, + organization_id=self.default_organization.organization_id, + role=[UserRole.ADMIN.value], + ) + + return member_data + + def handle_authorization_callback( + self, user: User, data: CallbackData, redirect_url: str = "" + ) -> Response: + return Response() + + def add_to_organization( + self, + request: Request, + user: User, + data: Optional[dict[str, Any]] = None, + ) -> MemberData: + member_data: MemberData = MemberData( + user_id=self.default_user.user_id, + organization_id=self.default_organization.organization_id, + ) + + return member_data + + def remove_users_from_organization( + self, + admin: OrganizationMember, + organization_id: str, + user_ids: list[str], + ) -> bool: + raise MethodNotImplemented() + + def user_organizations(self, request: Request) -> list[OrganizationData]: + organizationData: OrganizationData = OrganizationData( + id=self.default_organization.organization_id, + display_name=self.default_organization.display_name, + name=self.default_organization.name, + ) + return [organizationData] + + def get_organizations_by_user_id(self, id: str) -> list[OrganizationData]: + organizationData: OrganizationData = OrganizationData( + id=self.default_organization.organization_id, + display_name=self.default_organization.display_name, + name=self.default_organization.name, + ) + return [organizationData] + + def get_organization_role_of_user( + self, user_id: str, organization_id: str + ) -> list[str]: + return [UserRole.ADMIN.value] + + def is_organization_admin(self, member: OrganizationMember) -> bool: + """Check if the organization member has administrative privileges. + + Args: + member (OrganizationMember): The organization member to check. + + Returns: + bool: True if the user has administrative privileges, + False otherwise. + """ + try: + return UserRole(member.role) == UserRole.ADMIN + except ValueError: + return False + + def check_user_organization_association(self, user_email: str) -> None: + """Check if the user is already associated with any organizations. + + Raises: + - UserAlreadyAssociatedException: + If the user is already associated with organizations. + """ + return None + + def get_roles(self) -> list[UserRoleData]: + return [ + UserRoleData(name=UserRole.ADMIN.value), + UserRoleData(name=UserRole.USER.value), + ] + + def get_invitations(self, organization_id: str) -> list[MemberInvitation]: + raise MethodNotImplemented() + + def delete_invitation( + self, organization_id: str, invitation_id: str + ) -> bool: + raise MethodNotImplemented() + + def add_organization_user_role( + self, + admin: User, + organization_id: str, + user_id: str, + role_ids: list[str], + ) -> list[str]: + if admin.role == UserRole.ADMIN.value: + return role_ids + raise Forbidden + + def remove_organization_user_role( + self, + admin: User, + organization_id: str, + user_id: str, + role_ids: list[str], + ) -> list[str]: + if admin.role == UserRole.ADMIN.value: + return role_ids + raise Forbidden + + def get_organization_by_org_id(self, id: str) -> OrganizationData: + organizationData: OrganizationData = OrganizationData( + id=DefaultOrg.ORGANIZATION_NAME, + display_name=DefaultOrg.ORGANIZATION_NAME, + name=DefaultOrg.ORGANIZATION_NAME, + ) + return organizationData + + def get_user(self) -> User: + user = CacheService.get_user_session_info(DefaultOrg.MOCK_USER_EMAIL) + if not user: + try: + user = User.objects.get(email=DefaultOrg.MOCK_USER_EMAIL) + except User.DoesNotExist: + user = User( + username=DefaultOrg.MOCK_USER, + user_id=DefaultOrg.MOCK_USER_ID, + email=DefaultOrg.MOCK_USER_EMAIL, + ) + user.save() + if isinstance(user, User): + id = user.id + user_id = user.user_id + email = user.email + else: + id = user[Common.ID] + user_id = user[Common.USER_ID] + email = user[Common.USER_EMAIL] + + current_org = Common.PUBLIC_SCHEMA_NAME + + user_session_info: UserSessionInfo = UserSessionInfo( + id=id, + user_id=user_id, + email=email, + current_org=current_org, + ) + CacheService.set_user_session_info(user_session_info) + user_info = User(id=id, user_id=user_id, username=email, email=email) + return user_info + + def get_user_info(self, request: Request) -> Optional[UserInfo]: + user: User = request.user + if user: + return UserInfo( + id=user.id, + user_id=user.user_id, + name=user.username, + display_name=user.username, + email=user.email, + ) + else: + user = self.get_user() + return UserInfo( + id=user.id, + user_id=user.user_id, + name=user.username, + display_name=user.username, + email=user.email, + ) + + def get_user_session_info(self) -> UserSessionInfo: + user_session_info_dict = CacheService.get_user_session_info( + self.default_user.email + ) + if not user_session_info_dict: + user_session_info: UserSessionInfo = UserSessionInfo( + id=self.default_user.id, + user_id=self.default_user.user_id, + email=self.default_user.email, + current_org=self.default_organization.organization_id, + ) + CacheService.set_user_session_info(user_session_info) + else: + user_session_info = UserSessionInfo.from_dict( + user_session_info_dict + ) + return user_session_info + + def get_organization_info(self, org_id: str) -> Optional[Organization]: + return OrganizationService.get_organization_by_org_id(org_id=org_id) + + def make_organization_and_add_member( + self, + user_id: str, + user_name: str, + organization_name: Optional[str] = None, + display_name: Optional[str] = None, + ) -> Optional[OrganizationData]: + organization: OrganizationData = OrganizationData( + id=str(uuid.uuid4()), + display_name=DefaultOrg.MOCK_ORG, + name=DefaultOrg.MOCK_ORG, + ) + return organization + + def make_user_organization_name(self) -> str: + return str(uuid.uuid4()) + + def make_user_organization_display_name(self, user_name: str) -> str: + name = f"{user_name}'s" if user_name else "Your" + return f"{name} organization" + + def user_logout(self, request: HttpRequest) -> Response: + raise MethodNotImplemented() + + def get_user_id_from_token( + self, token: Optional[dict[str, Any]] + ) -> Response: + return DefaultOrg.MOCK_USER_ID + + def get_organization_members_by_org_id( + self, organization_id: str + ) -> list[MemberData]: + users: list[OrganizationMember] = OrganizationMember.objects.all() + return self.authentication_helper.list_of_members_from_user_model(users) + + def reset_user_password(self, user: User) -> ResetUserPasswordDto: + raise MethodNotImplemented() + + def invite_user( + self, + admin: OrganizationMember, + org_id: str, + email: str, + role: Optional[str] = None, + ) -> bool: + raise MethodNotImplemented() diff --git a/backend/account/cache_service.py b/backend/account/cache_service.py new file mode 100644 index 000000000..48f80fd5f --- /dev/null +++ b/backend/account/cache_service.py @@ -0,0 +1,134 @@ +from typing import Any, Optional, Union + +import redis +from account.custom_cache import CustomCache +from account.dto import UserSessionInfo +from django.conf import settings +from django.core.cache import cache + + +class CacheService: + def __init__(self) -> None: + self.cache = redis.Redis( + host=settings.REDIS_HOST, + port=int(settings.REDIS_PORT), + password=settings.REDIS_PASSWORD, + username=settings.REDIS_USER, + ) + + def get_a_key(self, key: str) -> Optional[Any]: + data = self.cache.get(str(key)) + if data is not None: + return data.decode("utf-8") + return data + + def set_a_key(self, key: str, value: Any) -> None: + self.cache.set( + str(key), + value, + int(settings.WORKFLOW_ACTION_EXPIRATION_TIME_IN_SECOND), + ) + + @staticmethod + def set_cookie(cookie: str, token: dict[str, Any]) -> None: + cache.set(cookie, token) + + @staticmethod + def get_cookie(cookie: str) -> dict[str, Any]: + data: dict[str, Any] = cache.get(cookie) + return data + + @staticmethod + def set_user_session_info( + user_session_info: Union[UserSessionInfo, dict[str, Any]] + ) -> None: + if isinstance(user_session_info, UserSessionInfo): + email = user_session_info.email + user_session = user_session_info.to_dict() + else: + email = user_session_info["email"] + user_session = user_session_info + session_info_key: str = CacheService.get_user_session_info_key(email) + cache.set( + session_info_key, + user_session, + int(settings.SESSION_EXPIRATION_TIME_IN_SECOND), + ) + + @staticmethod + def get_user_session_info(email: str) -> dict[str, Any]: + session_info_key: str = CacheService.get_user_session_info_key(email) + data: dict[str, Any] = cache.get(session_info_key) + return data + + @staticmethod + def get_user_session_info_key(email: str) -> str: + session_info_key: str = f"session:{email}" + return session_info_key + + @staticmethod + def check_a_key_exist(key: str, version: Any = None) -> bool: + data: bool = cache.has_key(key, version) + return data + + @staticmethod + def delete_a_key(key: str, version: Any = None) -> None: + cache.delete(key, version) + + @staticmethod + def set_user_organizations(user_id: str, organizations: list[str]) -> None: + key: str = f"{user_id}|organizations" + cache.set(key, list(organizations)) + + @staticmethod + def get_user_organizations(user_id: str) -> Any: + key: str = f"{user_id}|organizations" + return cache.get(key) + + @staticmethod + def remove_user_organizations(user_id: str) -> Any: + key: str = f"{user_id}|organizations" + return cache.delete(key) + + @staticmethod + def add_cookie_id_to_user(user_id: str, cookie_id: str) -> None: + custom_cache = CustomCache() + key: str = f"{user_id}|cookies" + custom_cache.rpush(key, cookie_id) + + @staticmethod + def remove_cookie_id_from_user(user_id: str, cookie_id: str) -> None: + custom_cache = CustomCache() + key: str = f"{user_id}|cookies" + custom_cache.lrem(key, cookie_id) + + @staticmethod + def remove_all_session_keys( + user_id: Optional[str] = None, + cookie_id: Optional[str] = None, + key: Optional[str] = None, + ) -> None: + if cookie_id is not None: + cache.delete(cookie_id) + if user_id is not None: + cache.delete(user_id) + CacheService.remove_user_organizations(user_id) + if key is not None: + cache.delete(key) + + # @staticmethod + # def get_cookie_ids_for_user(user_id: str) -> list[str]: + # custom_cache = CustomCache() + # key: str = f"{user_id}|cookies" + # cookie_ids = custom_cache.lrange(key, 0, -1) + # return cookie_ids + + +# KEY_FUNCTION for cache settings +def custom_key_function(key: str, key_prefix: str, version: int) -> str: + if version > 1: + return f"{key_prefix}:{version}:{key}" + if key_prefix: + return f"{key_prefix}:{key}" + else: + return key diff --git a/backend/account/constants.py b/backend/account/constants.py new file mode 100644 index 000000000..f962f0bfa --- /dev/null +++ b/backend/account/constants.py @@ -0,0 +1,74 @@ +class OAuthConstant: + TOKEN_USER_INFO_FEILD = "userinfo" + TOKEN_ORG_ID_FEILD = "org_id" + TOKEN_EMAIL_FEILD = "email" + TOKEN_Z_ID_FEILD = "sub" + TOKEN_USER_NAME_FEILD = "name" + TOKEN_PRIMARY_Z_ID_FEILD = "primary_sub" + + +class LoginConstant: + INVITATION = "invitation" + ORGANIZATION = "organization" + ORGANIZATION_NAME = "organization_name" + + +class Common: + NEXT_URL_VARIABLE = "next" + PUBLIC_SCHEMA_NAME = "public" + ID = "id" + USER_ID = "user_id" + USER_EMAIL = "email" + USER_EMAILS = "emails" + USER_IDS = "user_ids" + USER_ROLE = "role" + MAX_EMAIL_IN_REQUEST = 10 + + +class UserModel: + USER_ID = "user_id" + ID = "id" + + +class OrganizationMemberModel: + USER_ID = "user__user_id" + ID = "user__id" + + +class Cookie: + ORG_ID = "org_id" + Z_CODE = "z_code" + CSRFTOKEN = "csrftoken" + + +class ErrorMessage: + ORGANIZATION_EXIST = "Organization already exists" + DUPLICATE_API = "It appears that a duplicate call may have been made." + + +class DefaultOrg: + ORGANIZATION_NAME = "mock_org" + MOCK_ORG = "mock_org" + MOCK_USER = "mock_user" + MOCK_USER_ID = "mock_user_id" + MOCK_USER_EMAIL = "email@mock.com" + + +class PluginConfig: + PLUGINS_APP = "plugins" + AUTH_MODULE_PREFIX = "auth" + AUTH_PLUGIN_DIR = "authentication" + AUTH_MODULE = "module" + AUTH_METADATA = "metadata" + METADATA_SERVICE_CLASS = "service_class" + METADATA_IS_ACTIVE = "is_active" + + +class AuthoErrorCode: + """Error code reference + frontend/src/components/error/GenericError/GenericError.jsx.""" + + IDM = "IDM" + UMM = "UMM" + INF = "INF" + USF = "USF" diff --git a/backend/account/custom_auth_middleware.py b/backend/account/custom_auth_middleware.py new file mode 100644 index 000000000..d68e82548 --- /dev/null +++ b/backend/account/custom_auth_middleware.py @@ -0,0 +1,144 @@ +from typing import Optional + +from account.authentication_plugin_registry import AuthenticationPluginRegistry +from account.authentication_service import AuthenticationService +from account.cache_service import CacheService +from account.constants import Common, Cookie, DefaultOrg +from account.dto import UserSessionInfo +from account.models import User +from account.user import UserService +from backend.constants import RequestHeader +from django.conf import settings +from django.core.cache import cache +from django.db import connection +from django.http import HttpRequest, HttpResponse, JsonResponse +from tenant_account.organization_member_service import OrganizationMemberService + + +class CustomAuthMiddleware: + def __init__(self, get_response: HttpResponse): + self.get_response = get_response + # One-time configuration and initialization. + + def __call__(self, request: HttpRequest) -> HttpResponse: + user = None + request.user = user + + # Returns result without authenticated if added in whitelisted paths + if any( + request.path.startswith(path) for path in settings.WHITELISTED_PATHS + ): + return self.get_response(request) + + tenantAccessiblePublicPath = False + if any( + request.path.startswith(path) + for path in settings.TENANT_ACCESSIBLE_PUBLIC_PATHS + ): + tenantAccessiblePublicPath = True + + # Authenticating With API_KEY + x_api_key = request.headers.get(RequestHeader.X_API_KEY) + if ( + settings.INTERNAL_SERVICE_API_KEY + and x_api_key == settings.INTERNAL_SERVICE_API_KEY + ): # Should API Key be in settings or just env alone? + return self.get_response(request) + + if not AuthenticationPluginRegistry.is_plugin_available(): + self.without_authentication(request, user) + elif request.COOKIES: + self.authenticate_with_cookies(request, tenantAccessiblePublicPath) + if ( + request.user # type: ignore + and request.session + and "user" in request.session + ): + response = self.get_response(request) # type: ignore + return response + return JsonResponse({"message": "Unauthorized"}, status=401) + + def without_authentication( + self, request: HttpRequest, user: Optional[User] + ) -> None: + org_id = DefaultOrg.MOCK_ORG + user_id = DefaultOrg.MOCK_USER_ID + email = DefaultOrg.MOCK_USER_EMAIL + user_session_info = CacheService.get_user_session_info(email) + + if user is None: + try: + user_service = UserService() + user = user_service.get_user_by_user_id(user_id) + if not user: + member = user_service.get_user_by_user_id(user_id) + if member: + user = member.user + except AttributeError: + pass + if user is None: + authentication_service = AuthenticationService() + user = authentication_service.get_current_user() + + if user: + if not user_session_info: + user_info: UserSessionInfo = UserSessionInfo( + id=user.id, + user_id=user.user_id, + email=user.email, + current_org=org_id, + ) + CacheService.set_user_session_info(user_info) + user_session_info = CacheService.get_user_session_info(email) + + request.user = user + request.org_id = org_id + request.session["user"] = user_session_info + request.session.save() + + def authenticate_with_cookies( + self, + request: HttpRequest, + tenantAccessiblePublicPath: bool, + ) -> None: + z_code: str = request.COOKIES.get(Cookie.Z_CODE) + token = cache.get(z_code) if z_code else None + if not token: + return + + user_email = token["userinfo"]["email"] + user_session_info = CacheService.get_user_session_info(user_email) + if not user_session_info: + return + + current_org = user_session_info["current_org"] + if not current_org: + return + + if ( + current_org != connection.get_schema() + and not tenantAccessiblePublicPath + ): + return + + if ( + current_org == Common.PUBLIC_SCHEMA_NAME + or tenantAccessiblePublicPath + ): + user_service = UserService() + else: + organization_member_service = OrganizationMemberService() + member = organization_member_service.get_user_by_email(user_email) + if not member: + return + user_service = UserService() + + user = user_service.get_user_by_email(user_email) + + if not user: + return + + request.user = user + request.org_id = current_org + request.session["user"] = token + request.session.save() diff --git a/backend/account/custom_authentication.py b/backend/account/custom_authentication.py new file mode 100644 index 000000000..1f7cdcb6e --- /dev/null +++ b/backend/account/custom_authentication.py @@ -0,0 +1,13 @@ +from typing import Any + +from django.http import HttpRequest +from rest_framework.exceptions import AuthenticationFailed + + +def api_login_required(view_func: Any) -> Any: + def wrapper(request: HttpRequest, *args: Any, **kwargs: Any) -> Any: + if request.user and request.session and "user" in request.session: + return view_func(request, *args, **kwargs) + raise AuthenticationFailed("Unauthorized") + + return wrapper diff --git a/backend/account/custom_cache.py b/backend/account/custom_cache.py new file mode 100644 index 000000000..182f980f5 --- /dev/null +++ b/backend/account/custom_cache.py @@ -0,0 +1,12 @@ +from django_redis import get_redis_connection + + +class CustomCache: + def __init__(self) -> None: + self.cache = get_redis_connection("default") + + def rpush(self, key: str, value: str) -> None: + self.cache.rpush(key, value) + + def lrem(self, key: str, value: str) -> None: + self.cache.lrem(key, value) diff --git a/backend/account/custom_exceptions.py b/backend/account/custom_exceptions.py new file mode 100644 index 000000000..66e3671df --- /dev/null +++ b/backend/account/custom_exceptions.py @@ -0,0 +1,66 @@ +from typing import Optional + +from rest_framework.exceptions import APIException + + +class ConflictError(Exception): + def __init__(self, message: str) -> None: + self.message = message + super().__init__(self.message) + + +class MethodNotImplemented(APIException): + status_code = 501 + default_detail = "Method Not Implemented" + + +class DuplicateData(APIException): + status_code = 400 + default_detail = "Duplicate Data" + + def __init__( + self, detail: Optional[str] = None, code: Optional[int] = None + ): + if detail is not None: + self.detail = detail + if code is not None: + self.code = code + super().__init__(detail, code) + + +class TableNotExistError(APIException): + status_code = 400 + default_detail = "Unknown Table" + + def __init__( + self, detail: Optional[str] = None, code: Optional[int] = None + ): + if detail is not None: + self.detail = detail + if code is not None: + self.code = code + super().__init__() + + +class UserNotExistError(APIException): + status_code = 400 + default_detail = "Unknown User" + + def __init__( + self, detail: Optional[str] = None, code: Optional[int] = None + ): + if detail is not None: + self.detail = detail + if code is not None: + self.code = code + super().__init__() + + +class Forbidden(APIException): + status_code = 403 + default_detail = "Do not have permission to perform this action." + + +class UserAlreadyAssociatedException(APIException): + status_code = 400 + default_detail = "User is already associated with one organization." diff --git a/backend/account/dto.py b/backend/account/dto.py new file mode 100644 index 000000000..17037d8e9 --- /dev/null +++ b/backend/account/dto.py @@ -0,0 +1,130 @@ +from dataclasses import dataclass +from typing import Any, Optional + + +@dataclass +class MemberData: + user_id: str + email: Optional[str] = None + name: Optional[str] = None + picture: Optional[str] = None + role: Optional[list[str]] = None + organization_id: Optional[str] = None + + +@dataclass +class OrganizationData: + id: str + display_name: str + name: str + + +@dataclass +class CallbackData: + user_id: str + email: str + token: Any + + +@dataclass +class OrganizationSignupRequestBody: + name: str + display_name: str + organization_id: str + + +@dataclass +class OrganizationSignupResponse: + name: str + display_name: str + organization_id: str + created_at: str + + +@dataclass +class UserInfo: + email: str + user_id: str + id: Optional[str] = None + name: Optional[str] = None + display_name: Optional[str] = None + family_name: Optional[str] = None + picture: Optional[str] = None + + +@dataclass +class UserSessionInfo: + id: str + user_id: str + email: str + current_org: str + + @staticmethod + def from_dict(data: dict[str, Any]) -> "UserSessionInfo": + return UserSessionInfo( + id=data["id"], + user_id=data["user_id"], + email=data["email"], + current_org=data["current_org"], + ) + + def to_dict(self) -> Any: + return { + "id": self.id, + "user_id": self.user_id, + "email": self.email, + "current_org": self.current_org, + } + + +@dataclass +class GetUserReposne: + user: UserInfo + organizations: list[OrganizationData] + + +@dataclass +class ResetUserPasswordDto: + status: bool + message: str + + +@dataclass +class UserInviteResponse: + email: str + status: str + message: Optional[str] = None + + +@dataclass +class UserRoleData: + name: str + id: Optional[str] = None + description: Optional[str] = None + + +@dataclass +class MemberInvitation: + """Represents an invitation to join an organization in Auth0. + + Attributes: + id (str): The unique identifier for the invitation. + email (str): The user email. + roles (List[str]): The roles assigned to the invitee. + created_at (Optional[str]): The timestamp when the invitation + was created. + expires_at (Optional[str]): The timestamp when the invitation expires. + """ + + id: str + email: str + roles: list[str] + created_at: Optional[str] = None + expires_at: Optional[str] = None + + +@dataclass +class UserOrganizationRole: + user_id: str + role: UserRoleData + organization_id: str diff --git a/backend/account/enums.py b/backend/account/enums.py new file mode 100644 index 000000000..d8209ec2d --- /dev/null +++ b/backend/account/enums.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class UserRole(Enum): + USER = "user" + ADMIN = "admin" diff --git a/backend/account/exceptions.py b/backend/account/exceptions.py new file mode 100644 index 000000000..9f0b443b6 --- /dev/null +++ b/backend/account/exceptions.py @@ -0,0 +1,26 @@ +from rest_framework.exceptions import APIException + + +class UserIdNotExist(APIException): + status_code = 404 + default_detail = "User ID does not exist" + + +class UserAlreadyExistInOrganization(APIException): + status_code = 403 + default_detail = "User allready exist in the organization" + + +class OrganizationNotExist(APIException): + status_code = 404 + default_detail = "Organization does not exist" + + +class UnknownException(APIException): + status_code = 500 + default_detail = "An unexpected error occurred" + + +class BadRequestException(APIException): + status_code = 400 + default_detail = "Bad Request" diff --git a/backend/account/migrations/0001_initial.py b/backend/account/migrations/0001_initial.py new file mode 100644 index 000000000..a925b7fde --- /dev/null +++ b/backend/account/migrations/0001_initial.py @@ -0,0 +1,237 @@ +# Generated by Django 4.2.1 on 2023-07-18 10:39 + +import django.contrib.auth.models +import django.contrib.auth.validators +import django.db.models.deletion +import django.utils.timezone +import django_tenants.postgresql_backend.base +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + ("auth", "0012_alter_user_first_name_max_length"), + ] + + operations = [ + migrations.CreateModel( + name="User", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("password", models.CharField(max_length=128, verbose_name="password")), + ( + "last_login", + models.DateTimeField( + blank=True, null=True, verbose_name="last login" + ), + ), + ( + "is_superuser", + models.BooleanField( + default=False, + help_text="Designates that this user has all permissions without explicitly assigning them.", + verbose_name="superuser status", + ), + ), + ( + "username", + models.CharField( + error_messages={ + "unique": "A user with that username already exists." + }, + help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", + max_length=150, + unique=True, + validators=[ + django.contrib.auth.validators.UnicodeUsernameValidator() + ], + verbose_name="username", + ), + ), + ( + "first_name", + models.CharField( + blank=True, max_length=150, verbose_name="first name" + ), + ), + ( + "last_name", + models.CharField( + blank=True, max_length=150, verbose_name="last name" + ), + ), + ( + "email", + models.EmailField( + blank=True, max_length=254, verbose_name="email address" + ), + ), + ( + "is_staff", + models.BooleanField( + default=False, + help_text="Designates whether the user can log into this admin site.", + verbose_name="staff status", + ), + ), + ( + "is_active", + models.BooleanField( + default=True, + help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", + verbose_name="active", + ), + ), + ( + "date_joined", + models.DateTimeField( + default=django.utils.timezone.now, verbose_name="date joined" + ), + ), + ("user_id", models.CharField()), + ("project_storage_created", models.BooleanField(default=False)), + ("modified_at", models.DateTimeField(auto_now=True)), + ("created_at", models.DateTimeField(auto_now_add=True)), + ( + "created_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="created_users", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "groups", + models.ManyToManyField( + blank=True, + related_name="customuser_set", + related_query_name="customuser", + to="auth.group", + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="modified_users", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "user_permissions", + models.ManyToManyField( + blank=True, + related_name="customuser_set", + related_query_name="customuser", + to="auth.permission", + ), + ), + ], + options={ + "verbose_name": "user", + "verbose_name_plural": "users", + "abstract": False, + }, + managers=[ + ("objects", django.contrib.auth.models.UserManager()), + ], + ), + migrations.CreateModel( + name="Organization", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "schema_name", + models.CharField( + db_index=True, + max_length=63, + unique=True, + validators=[ + django_tenants.postgresql_backend.base._check_schema_name + ], + ), + ), + ("name", models.CharField(max_length=64)), + ("display_name", models.CharField(max_length=64)), + ("organization_id", models.CharField(max_length=64)), + ("modified_at", models.DateTimeField(auto_now=True)), + ("created_at", models.DateTimeField(auto_now=True)), + ( + "created_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="created_orgs", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="modified_orgs", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="Domain", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "domain", + models.CharField(db_index=True, max_length=253, unique=True), + ), + ("is_primary", models.BooleanField(db_index=True, default=True)), + ( + "tenant", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="domains", + to="account.organization", + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/backend/account/migrations/0002_auto_20230718_1040.py b/backend/account/migrations/0002_auto_20230718_1040.py new file mode 100644 index 000000000..59110ef85 --- /dev/null +++ b/backend/account/migrations/0002_auto_20230718_1040.py @@ -0,0 +1,39 @@ +# mypy: ignore-errors +# Generated by Django 4.2.1 on 2023-07-18 10:40 + +from django.contrib.auth.hashers import make_password +from django.db import migrations + + +def create_public_tenant_and_domain(apps, schema_editor): + Organization = apps.get_model("account", "Organization") + + # public tenant + tenant = Organization( + name="public", + display_name="public", + organization_id="public", + schema_name="public", + ) + tenant.save() + + User = apps.get_model("account", "User") + # public User admin + user = User( + username="admin", + email="admin@zipstack.com", + is_superuser=True, + is_staff=True, + password=make_password("ascon"), + ) + user.save() + + +class Migration(migrations.Migration): + dependencies = [ + ("account", "0001_initial"), + ] + + operations = [ + migrations.RunPython(create_public_tenant_and_domain), + ] diff --git a/backend/account/migrations/0003_platformkey.py b/backend/account/migrations/0003_platformkey.py new file mode 100644 index 000000000..fc8d80289 --- /dev/null +++ b/backend/account/migrations/0003_platformkey.py @@ -0,0 +1,65 @@ +# Generated by Django 4.2.1 on 2023-11-02 05:22 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + dependencies = [ + ("account", "0002_auto_20230718_1040"), + ] + + operations = [ + migrations.CreateModel( + name="PlatformKey", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ("key", models.UUIDField(default=uuid.uuid4)), + ( + "key_name", + models.CharField(blank=True, max_length=64, null=True, unique=True), + ), + ("is_active", models.BooleanField(default=False)), + ( + "created_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="created_keys", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="modified_keys", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "organization", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="related_org", + to="account.organization", + ), + ), + ], + ), + ] diff --git a/backend/account/migrations/0004_alter_platformkey_key_name_and_more.py b/backend/account/migrations/0004_alter_platformkey_key_name_and_more.py new file mode 100644 index 000000000..86df7e29b --- /dev/null +++ b/backend/account/migrations/0004_alter_platformkey_key_name_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.1 on 2023-11-15 11:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("account", "0003_platformkey"), + ] + + operations = [ + migrations.AlterField( + model_name="platformkey", + name="key_name", + field=models.CharField(blank=True, default="", max_length=64), + ), + migrations.AddConstraint( + model_name="platformkey", + constraint=models.UniqueConstraint( + fields=("key_name", "organization"), name="unique_key_name" + ), + ), + ] diff --git a/backend/account/migrations/0005_encryptionsecret.py b/backend/account/migrations/0005_encryptionsecret.py new file mode 100644 index 000000000..d8ff25b8a --- /dev/null +++ b/backend/account/migrations/0005_encryptionsecret.py @@ -0,0 +1,39 @@ +# Generated by Django 4.2.1 on 2024-02-13 11:52 + +from typing import Any + +from account.models import EncryptionSecret +from cryptography.fernet import Fernet +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("account", "0004_alter_platformkey_key_name_and_more"), + ] + + def initialize_secret(apps: Any, schema_editor: Any) -> None: + EncryptionSecret.objects.create( + key=Fernet.generate_key().decode("utf-8") + ) + + operations = [ + migrations.CreateModel( + name="EncryptionSecret", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("key", models.CharField(blank=True, max_length=64)), + ], + ), + migrations.RunPython( + initialize_secret, reverse_code=migrations.RunPython.noop + ), + ] diff --git a/backend/account/migrations/__init__.py b/backend/account/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/account/models.py b/backend/account/models.py new file mode 100644 index 000000000..c3bafc8fb --- /dev/null +++ b/backend/account/models.py @@ -0,0 +1,141 @@ +import uuid + +from backend.constants import FieldLengthConstants as FieldLength +from django.contrib.auth.models import AbstractUser, Group, Permission +from django.db import models +from django_tenants.models import DomainMixin, TenantMixin + +NAME_SIZE = 64 +KEY_SIZE = 64 + + +class Organization(TenantMixin): + """Stores data related to an organization. + + The fields created_by and modified_by is updated after a + :model:`account.User` is created. + """ + + name = models.CharField(max_length=NAME_SIZE) + display_name = models.CharField(max_length=NAME_SIZE) + organization_id = models.CharField(max_length=FieldLength.ORG_NAME_SIZE) + created_by = models.ForeignKey( + "User", + on_delete=models.SET_NULL, + related_name="created_orgs", + null=True, + blank=True, + ) + modified_by = models.ForeignKey( + "User", + on_delete=models.SET_NULL, + related_name="modified_orgs", + null=True, + blank=True, + ) + modified_at = models.DateTimeField(auto_now=True) + created_at = models.DateTimeField(auto_now=True) + + auto_create_schema = True + + +class Domain(DomainMixin): + pass + + +class User(AbstractUser): + """Stores data related to a user belonging to any organization. + + Every org, user is assumed to be unique. + """ + + # Third Party Authentication User ID + user_id = models.CharField() + project_storage_created = models.BooleanField(default=False) + created_by = models.ForeignKey( + "User", + on_delete=models.SET_NULL, + related_name="created_users", + null=True, + blank=True, + ) + modified_by = models.ForeignKey( + "User", + on_delete=models.SET_NULL, + related_name="modified_users", + null=True, + blank=True, + ) + modified_at = models.DateTimeField(auto_now=True) + created_at = models.DateTimeField(auto_now_add=True) + + # Specify a unique related_name for the groups field + groups = models.ManyToManyField( + Group, + related_name="customuser_set", + related_query_name="customuser", + blank=True, + ) + + # Specify a unique related_name for the user_permissions field + user_permissions = models.ManyToManyField( + Permission, + related_name="customuser_set", + related_query_name="customuser", + blank=True, + ) + + def __str__(self): # type: ignore + return f"User({self.id}, email: {self.email}, userId: {self.user_id})" + + +class PlatformKey(models.Model): + """Model to hold details of Platform keys. + + Only users with admin role are allowed to perform any operation + related keys. + """ + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + key = models.UUIDField(default=uuid.uuid4) + key_name = models.CharField( + max_length=KEY_SIZE, null=False, blank=True, default="" + ) + is_active = models.BooleanField(default=False) + organization = models.ForeignKey( + "Organization", + on_delete=models.SET_NULL, + related_name="related_org", + null=True, + blank=True, + ) + created_by = models.ForeignKey( + "User", + on_delete=models.SET_NULL, + related_name="created_keys", + null=True, + blank=True, + ) + modified_by = models.ForeignKey( + "User", + on_delete=models.SET_NULL, + related_name="modified_keys", + null=True, + blank=True, + ) + + class Meta: + constraints = [ + models.UniqueConstraint( + fields=["key_name", "organization"], + name="unique_key_name", + ), + ] + + +class EncryptionSecret(models.Model): + key = models.CharField( + max_length=KEY_SIZE, + null=False, + blank=True, + ) diff --git a/backend/account/organization.py b/backend/account/organization.py new file mode 100644 index 000000000..33d1305d0 --- /dev/null +++ b/backend/account/organization.py @@ -0,0 +1,42 @@ +import logging +from typing import Optional + +from account.models import Domain, Organization +from django.db import IntegrityError + +Logger = logging.getLogger(__name__) + + +class OrganizationService: + def __init__(self): # type: ignore + pass + + @staticmethod + def get_organization_by_org_id(org_id: str) -> Optional[Organization]: + try: + return Organization.objects.get(organization_id=org_id) # type: ignore + except Organization.DoesNotExist: + return None + + @staticmethod + def create_organization( + name: str, display_name: str, organization_id: str + ) -> Organization: + try: + organization: Organization = Organization( + name=name, + display_name=display_name, + organization_id=organization_id, + schema_name=organization_id, + ) + organization.save() + except IntegrityError as error: + Logger.info(f"[Duplicate Id] Failed to create Organization Error: {error}") + raise error + # Add one or more domains for the tenant + domain = Domain() + domain.domain = organization_id + domain.tenant = organization + domain.is_primary = True + domain.save() + return organization diff --git a/backend/account/serializer.py b/backend/account/serializer.py new file mode 100644 index 000000000..999c46316 --- /dev/null +++ b/backend/account/serializer.py @@ -0,0 +1,86 @@ +import re + +# from account.enums import Region +from account.models import Organization, User +from rest_framework import serializers + + +class OrganizationSignupSerializer(serializers.Serializer): + name = serializers.CharField(required=True, max_length=150) + display_name = serializers.CharField(required=True, max_length=150) + organization_id = serializers.CharField(required=True, max_length=30) + + def validate_organization_id(self, value): # type: ignore + if not re.match(r"^[a-z0-9_-]+$", value): + raise serializers.ValidationError( + "organization_code should only contain alphanumeric characters,_ and -." + ) + return value + + +class OrganizationCallbackSerializer(serializers.Serializer): + id = serializers.CharField(required=False) + + +class GetOrganizationsResponseSerializer(serializers.Serializer): + id = serializers.CharField() + display_name = serializers.CharField() + name = serializers.CharField() + # Add more fields as needed + + def to_representation(self, instance): # type: ignore + data = super().to_representation(instance) + # Modify the representation if needed + return data + + +class GetOrganizationMembersResponseSerializer(serializers.Serializer): + user_id = serializers.CharField() + email = serializers.CharField() + name = serializers.CharField() + picture = serializers.CharField() + # Add more fields as needed + + def to_representation(self, instance): # type: ignore + data = super().to_representation(instance) + # Modify the representation if needed + return data + + +class OrganizationSerializer(serializers.Serializer): + name = serializers.CharField() + organization_id = serializers.CharField() + + +class SetOrganizationsResponseSerializer(serializers.Serializer): + id = serializers.CharField() + email = serializers.CharField() + name = serializers.CharField() + display_name = serializers.CharField() + family_name = serializers.CharField() + picture = serializers.CharField() + # Add more fields as needed + + def to_representation(self, instance): # type: ignore + data = super().to_representation(instance) + # Modify the representation if needed + return data + + +class ModelTenantSerializer(serializers.ModelSerializer): + class Meta: + model = Organization + fields = fields = ("name", "created_on") + + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = ("id", "email") + + +class OrganizationSignupResponseSerializer(serializers.Serializer): + name = serializers.CharField() + display_name = serializers.CharField() + organization_id = serializers.CharField() + created_at = serializers.CharField() diff --git a/backend/account/templates/index.html b/backend/account/templates/index.html new file mode 100644 index 000000000..ffa0b6085 --- /dev/null +++ b/backend/account/templates/index.html @@ -0,0 +1,11 @@ + + + + + ZipstackID Django App Example + + +

Welcome Guest

+

Login

+ + diff --git a/backend/account/tests.py b/backend/account/tests.py new file mode 100644 index 000000000..a39b155ac --- /dev/null +++ b/backend/account/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/backend/account/urls.py b/backend/account/urls.py new file mode 100644 index 000000000..8cc60e65c --- /dev/null +++ b/backend/account/urls.py @@ -0,0 +1,20 @@ +from account.views import ( + callback, + create_organization, + get_organizations, + login, + logout, + set_organization, + signup, +) +from django.urls import path + +urlpatterns = [ + path("login", login, name="login"), + path("signup", signup, name="signup"), + path("logout", logout, name="logout"), + path("callback", callback, name="callback"), + path("organization", get_organizations, name="get_organizations"), + path("organization//set", set_organization, name="set_organization"), + path("organization/create", create_organization, name="create_organization"), +] diff --git a/backend/account/user.py b/backend/account/user.py new file mode 100644 index 000000000..f875d4572 --- /dev/null +++ b/backend/account/user.py @@ -0,0 +1,50 @@ +import logging +from typing import Any, Optional + +from account.models import User +from django.db import IntegrityError + +Logger = logging.getLogger(__name__) + + +class UserService: + def __init__( + self, + ) -> None: + pass + + def create_user(self, email: str, user_id: str) -> User: + try: + user: User = User(email=email, user_id=user_id, username=email) + user.save() + except IntegrityError as error: + Logger.info(f"[Duplicate Id] Failed to create User Error: {error}") + raise error + return user + + def get_user_by_email(self, email: str) -> Optional[User]: + try: + user: User = User.objects.get(email=email) + return user + except User.DoesNotExist: + return None + + def get_user_by_user_id(self, user_id: str) -> Any: + try: + return User.objects.get(user_id=user_id) + except User.DoesNotExist: + return None + + def get_user_by_id(self, id: str) -> Any: + """Retrieve a user by their ID, taking into account the schema context. + + Args: + id (str): The ID of the user. + + Returns: + Any: The user object if found, or None if not found. + """ + try: + return User.objects.get(id=id) + except User.DoesNotExist: + return None diff --git a/backend/account/views.py b/backend/account/views.py new file mode 100644 index 000000000..50b2b82d6 --- /dev/null +++ b/backend/account/views.py @@ -0,0 +1,125 @@ +import logging +from typing import Any + +from account.authentication_controller import AuthenticationController +from account.dto import ( + OrganizationSignupRequestBody, + OrganizationSignupResponse, +) +from account.models import Organization +from account.organization import OrganizationService +from account.serializer import ( + OrganizationSignupResponseSerializer, + OrganizationSignupSerializer, +) +from rest_framework import status +from rest_framework.decorators import api_view +from rest_framework.request import Request +from rest_framework.response import Response + +Logger = logging.getLogger(__name__) + + +@api_view(["POST"]) +def create_organization(request: Request) -> Response: + serializer = OrganizationSignupSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + try: + requestBody: OrganizationSignupRequestBody = makeSignupRequestParams( + serializer + ) + + organization: Organization = OrganizationService.create_organization( + requestBody.name, + requestBody.display_name, + requestBody.organization_id, + ) + response = makeSignupResponse(organization) + return Response( + status=status.HTTP_201_CREATED, + data={"message": "success", "tenant": response}, + ) + except Exception as error: + Logger.error(error) + return Response( + status=status.HTTP_500_INTERNAL_SERVER_ERROR, data="Unknown Error" + ) + + +@api_view(["GET"]) +def callback(request: Request) -> Response: + auth_controller = AuthenticationController() + return auth_controller.authorization_callback(request) + + +@api_view(["GET"]) +def login(request: Request) -> Response: + auth_controller = AuthenticationController() + return auth_controller.user_login(request) + + +@api_view(["GET"]) +def signup(request: Request) -> Response: + auth_controller = AuthenticationController() + return auth_controller.user_signup(request) + + +@api_view(["GET"]) +def logout(request: Request) -> Response: + auth_controller = AuthenticationController() + return auth_controller.user_logout(request) + + +@api_view(["GET"]) +def get_organizations(request: Request) -> Response: + """get_organizations. + + Retrieve the list of organizations to which the user belongs. + Args: + request (HttpRequest): _description_ + + Returns: + Response: A list of organizations with associated information. + """ + auth_controller = AuthenticationController() + return auth_controller.user_organizations(request) + + +@api_view(["POST"]) +def set_organization(request: Request, id: str) -> Response: + """set_organization. + + Set the current organization to use. + Args: + request (HttpRequest): _description_ + id (String): organization Id + + Returns: + Response: Contains the User and Current organization details. + """ + + auth_controller = AuthenticationController() + return auth_controller.set_user_organization(request, id) + + +def makeSignupRequestParams( + serializer: OrganizationSignupSerializer, +) -> OrganizationSignupRequestBody: + return OrganizationSignupRequestBody( + serializer.validated_data["name"], + serializer.validated_data["display_name"], + serializer.validated_data["organization_id"], + ) + + +def makeSignupResponse( + organization: Organization, +) -> Any: + return OrganizationSignupResponseSerializer( + OrganizationSignupResponse( + organization.name, + organization.display_name, + organization.organization_id, + organization.created_at, + ) + ).data diff --git a/backend/adapter_processor/__init__.py b/backend/adapter_processor/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/adapter_processor/adapter_processor.py b/backend/adapter_processor/adapter_processor.py new file mode 100644 index 000000000..b44088a64 --- /dev/null +++ b/backend/adapter_processor/adapter_processor.py @@ -0,0 +1,280 @@ +import json +import logging +from typing import Any, Optional + +import adapter_processor +from account.models import User +from adapter_processor.constants import AdapterKeys +from adapter_processor.exceptions import ( + InternalServiceError, + InValidAdapterId, + TestAdapterException, + TestAdapterInputException, +) +from django.conf import settings +from django.core.exceptions import ObjectDoesNotExist +from platform_settings.exceptions import ActiveKeyNotFound +from platform_settings.platform_auth_service import ( + PlatformAuthenticationService, +) +from unstract.adapters.adapterkit import Adapterkit +from unstract.adapters.base import Adapter +from unstract.adapters.enums import AdapterTypes +from unstract.adapters.exceptions import AdapterError +from unstract.adapters.x2text.constants import X2TextConstants + +from .models import AdapterInstance + +logger = logging.getLogger(__name__) + + +class AdapterProcessor: + @staticmethod + def get_json_schema(adapter_id: str) -> dict[str, Any]: + """Function to return JSON Schema for Adapters.""" + schema_details: dict[str, Any] = {} + updated_adapters = AdapterProcessor.__fetch_adapters_by_key_value( + AdapterKeys.ID, adapter_id + ) + if len(updated_adapters) != 0: + try: + schema_details[AdapterKeys.JSON_SCHEMA] = json.loads( + updated_adapters[0].get(AdapterKeys.JSON_SCHEMA) + ) + except Exception as exc: + logger.error(f"Error occured while parsing JSON Schema : {exc}") + raise InternalServiceError() + else: + logger.error( + f"Invalid adapter Id : {adapter_id} while fetching JSON Schema" + ) + raise InValidAdapterId() + return schema_details + + @staticmethod + def get_all_supported_adapters(type: str) -> list[dict[Any, Any]]: + """Function to return list of all supported adapters.""" + supported_adapters = [] + updated_adapters = [] + updated_adapters = AdapterProcessor.__fetch_adapters_by_key_value( + AdapterKeys.ADAPTER_TYPE, type + ) + for each_adapter in updated_adapters: + supported_adapters.append( + { + AdapterKeys.ID: each_adapter.get(AdapterKeys.ID), + AdapterKeys.NAME: each_adapter.get(AdapterKeys.NAME), + AdapterKeys.DESCRIPTION: each_adapter.get( + AdapterKeys.DESCRIPTION + ), + AdapterKeys.ICON: each_adapter.get(AdapterKeys.ICON), + AdapterKeys.ADAPTER_TYPE: each_adapter.get( + AdapterKeys.ADAPTER_TYPE + ), + } + ) + return supported_adapters + + @staticmethod + def get_adapter_data_with_key(adapter_id: str, key_value: str) -> Any: + """Generic Function to get adapter data with provided key.""" + updated_adapters = AdapterProcessor.__fetch_adapters_by_key_value( + "id", adapter_id + ) + if len(updated_adapters) == 0: + logger.error( + f"Invalid adapter ID {adapter_id} while invoking utility" + ) + raise InValidAdapterId() + return AdapterProcessor.__fetch_adapters_by_key_value("id", adapter_id)[ + 0 + ].get(key_value) + + @staticmethod + def test_adapter(adapter_id: str, adapter_metadata: dict[str, Any]) -> bool: + logger.info(f"Testing adapter: {adapter_id}") + try: + adapter_class = Adapterkit().get_adapter_class_by_adapter_id( + adapter_id + ) + + if ( + adapter_metadata.pop(AdapterKeys.ADAPTER_TYPE) + == AdapterKeys.X2TEXT + ): + adapter_metadata[ + X2TextConstants.X2TEXT_HOST + ] = settings.X2TEXT_HOST + adapter_metadata[ + X2TextConstants.X2TEXT_PORT + ] = settings.X2TEXT_PORT + platform_key = ( + PlatformAuthenticationService.get_active_platform_key() + ) + adapter_metadata[ + X2TextConstants.PLATFORM_SERVICE_API_KEY + ] = str(platform_key.key) + + adapter_instance = adapter_class(adapter_metadata) + test_result: bool = adapter_instance.test_connection() + logger.info(f"{adapter_id} test result: {test_result}") + return test_result + except ActiveKeyNotFound: + raise + except Exception as e: + logger.error(f"Error while testing {adapter_id}: {e}") + if isinstance(e, AdapterError): + raise TestAdapterInputException(str(e.message)) + elif isinstance(e, ActiveKeyNotFound): + raise e + else: + raise TestAdapterException() + + @staticmethod + def __fetch_adapters_by_key_value(key: str, value: Any) -> Adapter: + """Fetches a list of adapters that have an attribute matching key and + value.""" + logger.info(f"Fetching adapter list for {key} with {value}") + adapter_kit = Adapterkit() + adapters = adapter_kit.get_adapters_list() + return [iterate for iterate in adapters if iterate[key] == value] + + @staticmethod + def set_default_triad(default_triad: dict[str, str], user: User) -> None: + filter_params: dict[str, Any] = {} + + try: + for key in default_triad: + filter_params.clear() + adapter_id = default_triad[key] + # Query rows where adapter_type=X and is_default=True + if key == AdapterKeys.LLM_DEFAULT: + adapter_type = AdapterTypes.LLM.name + elif key == AdapterKeys.EMBEDDING_DEFAULT: + adapter_type = AdapterTypes.EMBEDDING.name + elif key == AdapterKeys.VECTOR_DB_DEFAULT: + adapter_type = AdapterTypes.VECTOR_DB.name + + filter_params["adapter_type"] = adapter_type + filter_params["is_default"] = True + filter_params["created_by"] = user + + AdapterInstance.objects.filter(**filter_params).update( + is_default=False + ) + + # Update the adapter_id in the incoming + # list to set is_default=True + filter_params.clear() + try: + new_adapter_default: AdapterInstance = ( + AdapterInstance.objects.get(pk=adapter_id) + ) + new_adapter_default.is_default = True + new_adapter_default.save() + except ( + adapter_processor.models.AdapterInstance.DoesNotExist + ) as e: + logger.error( + f"Error while retrieving adapter: {adapter_id} " + f"reason: {e}" + ) + raise InValidAdapterId() + logger.info("Changed defaults successfully") + except Exception as e: + logger.error(f"Unable to save defaults because: {e}") + if isinstance(e, InValidAdapterId): + raise e + else: + raise InternalServiceError() + + @staticmethod + def get_adapter_instance_by_id(adapter_instance_id: str) -> Adapter: + """Get the adapter instance by its ID. + + Parameters: + - adapter_instance_id (str): The ID of the adapter instance. + + Returns: + - Adapter: The adapter instance with the specified ID. + + Raises: + - Exception: If there is an error while fetching the adapter instance. + """ + try: + adapter = AdapterInstance.objects.get(id=adapter_instance_id) + except Exception as e: + logger.error(f"Unable to fetch adapter: {e}") + if not adapter: + logger.error("Unable to fetch adapter") + return adapter.adapter_name + + @staticmethod + def get_adapters_by_type( + adapter_type: AdapterTypes, user: User + ) -> list[AdapterInstance]: + """Get a list of adapters by their type. + + Parameters: + - adapter_type (AdapterTypes): The type of adapters to retrieve. + + Returns: + - list[AdapterInstance]: A list of AdapterInstance objects that match + the specified adapter type. + """ + adapters: list[AdapterInstance] = AdapterInstance.objects.filter( + adapter_type=adapter_type.value, created_by=user + ) + return adapters + + @staticmethod + def get_adapter_by_name_and_type( + adapter_type: AdapterTypes, + adapter_name: Optional[str] = None, + ) -> Optional[AdapterInstance]: + """Get the adapter instance by its name and type. + + Parameters: + - adapter_name (str): The name of the adapter instance. + - adapter_type (AdapterTypes): The type of the adapter instance. + + Returns: + - AdapterInstance: The adapter with the specified name and type. + """ + if adapter_name: + adapter: AdapterInstance = AdapterInstance.objects.get( + adapter_name=adapter_name, adapter_type=adapter_type.value + ) + else: + try: + adapter = AdapterInstance.objects.get( + adapter_type=adapter_type.value, is_default=True + ) + except AdapterInstance.DoesNotExist: + return None + return adapter + + @staticmethod + def get_default_adapters(user: User) -> list[AdapterInstance]: + """Retrieve a list of default adapter instances. This method queries + the database to fetch all adapter instances marked as default. + + Raises: + InternalServiceError: If an unexpected error occurs during + the database query. + + Returns: + list[AdapterInstance]: A list of AdapterInstance objects that are + marked as default. + """ + try: + adapters: list[AdapterInstance] = AdapterInstance.objects.filter( + is_default=True, created_by=user + ) + return adapters + except ObjectDoesNotExist as e: + logger.error(f"No default adapters found: {e}") + raise InternalServiceError("No default adapters found") + except Exception as e: + logger.error(f"Error occurred while fetching default adapters: {e}") + raise InternalServiceError("Error fetching default adapters") diff --git a/backend/adapter_processor/constants.py b/backend/adapter_processor/constants.py new file mode 100644 index 000000000..429d67b3a --- /dev/null +++ b/backend/adapter_processor/constants.py @@ -0,0 +1,23 @@ +class AdapterKeys: + JSON_SCHEMA = "json_schema" + ADAPTER_TYPE = "adapter_type" + IS_DEFAULT = "is_default" + LLM = "LLM" + X2TEXT = "X2TEXT" + VECTOR_DB = "VECTOR_DB" + EMBEDDING = "EMBEDDING" + NAME = "name" + DESCRIPTION = "description" + ICON = "icon" + ADAPTER_ID = "adapter_id" + ADAPTER_METADATA = "adapter_metadata" + ADAPTER_METADATA_B = "adapter_metadata_b" + ID = "id" + IS_VALID = "is_valid" + LLM_DEFAULT = "llm_default" + VECTOR_DB_DEFAULT = "vector_db_default" + EMBEDDING_DEFAULT = "embedding_default" + ADAPTER_NAME_EXISTS = ( + "Configuration with this ID already exists. " + "Please try with a different ID" + ) diff --git a/backend/adapter_processor/exceptions.py b/backend/adapter_processor/exceptions.py new file mode 100644 index 000000000..2feb8a298 --- /dev/null +++ b/backend/adapter_processor/exceptions.py @@ -0,0 +1,55 @@ +from backend.exceptions import UnstractBaseException +from rest_framework.exceptions import APIException + + +class IdIsMandatory(APIException): + status_code = 400 + default_detail = "ID is Mandatory." + + +class InValidType(APIException): + status_code = 400 + default_detail = "Type is not Valid." + + +class InValidAdapterId(APIException): + status_code = 400 + default_detail = "Adapter ID is not Valid." + + +class JSONParseException(APIException): + status_code = 500 + default_detail = "Exception occured while Parsing JSON Schema." + + +class InternalServiceError(APIException): + status_code = 500 + default_detail = "Internal Service error" + + +class CannotDeleteDefaultAdapter(APIException): + status_code = 500 + default_detail = ( + "This is configured as default and cannot be deleted. " + "Please configure a different default before you try again!" + ) + + +class UniqueConstraintViolation(APIException): + status_code = 400 + default_detail = "Unique constraint violated" + + +class TestAdapterException(APIException): + status_code = 500 + default_detail = "Error while testing adapter." + + +class TestAdapterInputException(UnstractBaseException): + status_code = 400 + default_detail = "Connection test failed using the given configuration data" + + +class ErrorFetchingAdapterData(UnstractBaseException): + status_code = 400 + default_detail = "Error while fetching adapter data." diff --git a/backend/adapter_processor/migrations/0001_initial.py b/backend/adapter_processor/migrations/0001_initial.py new file mode 100644 index 000000000..1b954e60b --- /dev/null +++ b/backend/adapter_processor/migrations/0001_initial.py @@ -0,0 +1,109 @@ +# Generated by Django 4.2.1 on 2024-01-23 11:18 + +import uuid + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="AdapterInstance", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "id", + models.UUIDField( + db_comment="Unique identifier for the Adapter Instance", + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "adapter_name", + models.TextField( + db_comment="Name of the Adapter Instance", + max_length=128, + ), + ), + ( + "adapter_id", + models.CharField( + db_comment="Unique identifier of the Adapter", + default="", + max_length=128, + ), + ), + ( + "adapter_metadata", + models.JSONField( + db_column="adapter_metadata", + db_comment="JSON adapter metadata submitted by the user", + default=dict, + ), + ), + ( + "adapter_type", + models.CharField( + choices=[ + ("UNKNOWN", "UNKNOWN"), + ("LLM", "LLM"), + ("EMBEDDING", "EMBEDDING"), + ("VECTOR_DB", "VECTOR_DB"), + ], + db_comment="Type of adapter LLM/EMBEDDING/VECTOR_DB", + ), + ), + ( + "is_active", + models.BooleanField( + db_comment="Is the adapter instance currently being used", + default=False, + ), + ), + ( + "is_default", + models.BooleanField( + db_comment="Is the adapter instance default", + default=False, + ), + ), + ( + "created_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="created_adapters", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="modified_adapters", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "verbose_name": "adapter_adapterinstance", + "verbose_name_plural": "adapter_adapterinstance", + "db_table": "adapter_adapterinstance", + }, + ), + ] diff --git a/backend/adapter_processor/migrations/0002_adapterinstance_unique_adapter.py b/backend/adapter_processor/migrations/0002_adapterinstance_unique_adapter.py new file mode 100644 index 000000000..5b1c46593 --- /dev/null +++ b/backend/adapter_processor/migrations/0002_adapterinstance_unique_adapter.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.1 on 2024-01-20 08:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("adapter_processor", "0001_initial"), + ] + + operations = [ + migrations.AddConstraint( + model_name="adapterinstance", + constraint=models.UniqueConstraint( + fields=("adapter_name", "adapter_type"), name="unique_adapter" + ), + ), + ] diff --git a/backend/adapter_processor/migrations/0003_adapterinstance_adapter_metadata_b.py b/backend/adapter_processor/migrations/0003_adapterinstance_adapter_metadata_b.py new file mode 100644 index 000000000..5f65c0040 --- /dev/null +++ b/backend/adapter_processor/migrations/0003_adapterinstance_adapter_metadata_b.py @@ -0,0 +1,41 @@ +# Generated by Django 4.2.1 on 2024-02-13 13:09 + +import json +from typing import Any + +from account.models import EncryptionSecret +from adapter_processor.models import AdapterInstance +from cryptography.fernet import Fernet +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("adapter_processor", "0002_adapterinstance_unique_adapter"), + ("account", "0005_encryptionsecret"), + ] + + def EncryptCredentials(apps: Any, schema_editor: Any) -> None: + encryption_secret: EncryptionSecret = EncryptionSecret.objects.get() + f: Fernet = Fernet(encryption_secret.key.encode("utf-8")) + queryset = AdapterInstance.objects.all() + + for obj in queryset: # type: ignore + # Access attributes of the object + + print(f"Object ID: {obj.id}, Name: {obj.adapter_name}") + if hasattr(obj, "adapter_metadata"): + json_string: str = json.dumps(obj.adapter_metadata) + obj.adapter_metadata_b = f.encrypt(json_string.encode("utf-8")) + obj.save() + + operations = [ + migrations.AddField( + model_name="adapterinstance", + name="adapter_metadata_b", + field=models.BinaryField(null=True), + ), + migrations.RunPython( + EncryptCredentials, reverse_code=migrations.RunPython.noop + ), + ] diff --git a/backend/adapter_processor/migrations/0004_alter_adapterinstance_adapter_type.py b/backend/adapter_processor/migrations/0004_alter_adapterinstance_adapter_type.py new file mode 100644 index 000000000..6321d6219 --- /dev/null +++ b/backend/adapter_processor/migrations/0004_alter_adapterinstance_adapter_type.py @@ -0,0 +1,26 @@ +# Generated by Django 4.2.1 on 2024-02-23 09:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("adapter_processor", "0003_adapterinstance_adapter_metadata_b"), + ] + + operations = [ + migrations.AlterField( + model_name="adapterinstance", + name="adapter_type", + field=models.CharField( + choices=[ + ("UNKNOWN", "UNKNOWN"), + ("LLM", "LLM"), + ("EMBEDDING", "EMBEDDING"), + ("VECTOR_DB", "VECTOR_DB"), + ("X2TEXT", "X2TEXT"), + ], + db_comment="Type of adapter LLM/EMBEDDING/VECTOR_DB", + ), + ), + ] diff --git a/backend/adapter_processor/migrations/__init__.py b/backend/adapter_processor/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/adapter_processor/models.py b/backend/adapter_processor/models.py new file mode 100644 index 000000000..ac511c256 --- /dev/null +++ b/backend/adapter_processor/models.py @@ -0,0 +1,78 @@ +import uuid + +from account.models import User +from django.db import models +from unstract.adapters.enums import AdapterTypes +from utils.models.base_model import BaseModel + +ADAPTER_NAME_SIZE = 128 +VERSION_NAME_SIZE = 64 +ADAPTER_ID_LENGTH = 128 + + +class AdapterInstance(BaseModel): + id = models.UUIDField( + primary_key=True, + default=uuid.uuid4, + editable=False, + db_comment="Unique identifier for the Adapter Instance", + ) + adapter_name = models.TextField( + max_length=ADAPTER_NAME_SIZE, + null=False, + blank=False, + db_comment="Name of the Adapter Instance", + ) + adapter_id = models.CharField( + max_length=ADAPTER_ID_LENGTH, + default="", + db_comment="Unique identifier of the Adapter", + ) + + # TODO to be removed once the migration for encryption + adapter_metadata = models.JSONField( + db_column="adapter_metadata", + null=False, + blank=False, + default=dict, + db_comment="JSON adapter metadata submitted by the user", + ) + adapter_metadata_b = models.BinaryField(null=True) + adapter_type = models.CharField( + choices=[(tag.value, tag.name) for tag in AdapterTypes], + db_comment="Type of adapter LLM/EMBEDDING/VECTOR_DB", + ) + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="created_adapters", + null=True, + blank=True, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="modified_adapters", + null=True, + blank=True, + ) + + is_active = models.BooleanField( + default=False, + db_comment="Is the adapter instance currently being used", + ) + is_default = models.BooleanField( + default=False, + db_comment="Is the adapter instance default", + ) + + class Meta: + verbose_name = "adapter_adapterinstance" + verbose_name_plural = "adapter_adapterinstance" + db_table = "adapter_adapterinstance" + constraints = [ + models.UniqueConstraint( + fields=["adapter_name", "adapter_type"], + name="unique_adapter", + ), + ] diff --git a/backend/adapter_processor/serializers.py b/backend/adapter_processor/serializers.py new file mode 100644 index 000000000..a719d23f1 --- /dev/null +++ b/backend/adapter_processor/serializers.py @@ -0,0 +1,91 @@ +import json +from typing import Any + +from account.models import EncryptionSecret +from adapter_processor.adapter_processor import AdapterProcessor +from adapter_processor.constants import AdapterKeys +from cryptography.fernet import Fernet +from rest_framework import serializers +from unstract.adapters.constants import Common as common +from utils.serializer_utils import SerializerUtils + +from backend.constants import FieldLengthConstants as FLC +from backend.serializers import AuditSerializer + +from .models import AdapterInstance + + +class TestAdapterSerializer(serializers.Serializer): + adapter_id = serializers.CharField(max_length=FLC.ADAPTER_ID_LENGTH) + adapter_metadata = serializers.JSONField() + adapter_type = serializers.JSONField() + + +class BaseAdapterSerializer(AuditSerializer): + class Meta: + model = AdapterInstance + fields = "__all__" + + +class DefaultAdapterSerializer(serializers.Serializer): + llm_default = serializers.CharField( + max_length=FLC.UUID_LENGTH, required=False + ) + embedding_default = serializers.CharField( + max_length=FLC.UUID_LENGTH, required=False + ) + vector_db_default = serializers.CharField( + max_length=FLC.UUID_LENGTH, required=False + ) + + +class AdapterInstanceSerializer(BaseAdapterSerializer): + """Inherits BaseAdapterSerializer. + + Used for GET/POST request for adapter + """ + + class Meta(BaseAdapterSerializer.Meta): + pass + + def to_internal_value(self, data: dict[str, Any]) -> dict[str, Any]: + encryption_secret: EncryptionSecret = EncryptionSecret.objects.get() + f: Fernet = Fernet(encryption_secret.key.encode("utf-8")) + json_string: str = json.dumps(data.pop(AdapterKeys.ADAPTER_METADATA)) + + data[AdapterKeys.ADAPTER_METADATA_B] = f.encrypt( + json_string.encode("utf-8") + ) + + return data + + def to_representation(self, instance: AdapterInstance) -> dict[str, str]: + rep: dict[str, str] = super().to_representation(instance) + + if SerializerUtils.check_context_for_GET_or_POST(context=self.context): + rep[common.ICON] = AdapterProcessor.get_adapter_data_with_key( + instance.adapter_id, common.ICON + ) + rep.pop(AdapterKeys.ADAPTER_METADATA_B) + return rep + + +class AdapterDetailSerializer(BaseAdapterSerializer): + """Inherits BaseAdapterSerializer. + + Used for GET/UPDATE/DELETE request for adapter/ + """ + + def to_representation(self, instance: AdapterInstance) -> dict[str, str]: + rep: dict[str, str] = super().to_representation(instance) + + encryption_secret: EncryptionSecret = EncryptionSecret.objects.get() + f: Fernet = Fernet(encryption_secret.key.encode("utf-8")) + + rep.pop(AdapterKeys.ADAPTER_METADATA_B) + adapter_metadata = json.loads( + f.decrypt(bytes(instance.adapter_metadata_b).decode("utf-8")) + ) + rep[AdapterKeys.ADAPTER_METADATA] = adapter_metadata + + return rep diff --git a/backend/adapter_processor/urls.py b/backend/adapter_processor/urls.py new file mode 100644 index 000000000..83ce6ce64 --- /dev/null +++ b/backend/adapter_processor/urls.py @@ -0,0 +1,34 @@ +from adapter_processor.views import ( + AdapterDetailViewSet, + AdapterInstanceViewSet, + AdapterViewSet, + DefaultAdapterViewSet, +) +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns + +adapter = AdapterViewSet.as_view({"get": "list"}) +default_triad = DefaultAdapterViewSet.as_view( + {"post": "configure_default_triad"} +) +adapter_schema = AdapterViewSet.as_view({"get": "get_adapter_schema"}) +adapter_list = AdapterInstanceViewSet.as_view({"post": "create", "get": "list"}) +adapter_detail = AdapterDetailViewSet.as_view( + { + "get": "retrieve", + "put": "update", + "patch": "partial_update", + "delete": "destroy", + } +) +adapter_test = AdapterViewSet.as_view({"post": "test"}) +urlpatterns = format_suffix_patterns( + [ + path("adapter_schema/", adapter_schema, name="get_adapter_schema"), + path("supported_adapters/", adapter, name="adapter-list"), + path("adapter/", adapter_list, name="adapter-list"), + path("adapter/default_triad/", default_triad, name="default_triad"), + path("adapter//", adapter_detail, name="adapter_detail"), + path("test_adapters/", adapter_test, name="adapter-test"), + ] +) diff --git a/backend/adapter_processor/views.py b/backend/adapter_processor/views.py new file mode 100644 index 000000000..2009527af --- /dev/null +++ b/backend/adapter_processor/views.py @@ -0,0 +1,182 @@ +import logging +from typing import Any, Optional + +from account.models import User +from adapter_processor.adapter_processor import AdapterProcessor +from adapter_processor.constants import AdapterKeys +from adapter_processor.exceptions import ( + CannotDeleteDefaultAdapter, + IdIsMandatory, + InValidType, + UniqueConstraintViolation, +) +from adapter_processor.serializers import ( + AdapterDetailSerializer, + AdapterInstanceSerializer, + DefaultAdapterSerializer, + TestAdapterSerializer, +) +from django.db import IntegrityError +from django.db.models import QuerySet +from django.http.response import HttpResponse +from permissions.permission import IsOwner +from rest_framework import status +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning +from rest_framework.viewsets import GenericViewSet, ModelViewSet +from utils.filtering import FilterHelper + +from .constants import AdapterKeys as constant +from .exceptions import InternalServiceError +from .models import AdapterInstance + +logger = logging.getLogger(__name__) + + +class DefaultAdapterViewSet(ModelViewSet): + versioning_class = URLPathVersioning + serializer_class = DefaultAdapterSerializer + + def configure_default_triad( + self, request: Request, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> HttpResponse: + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + # Convert request data to json + default_triad = request.data + AdapterProcessor.set_default_triad(default_triad, request.user) + return Response(status=status.HTTP_200_OK) + + +class AdapterViewSet(GenericViewSet): + versioning_class = URLPathVersioning + serializer_class = TestAdapterSerializer + + def list( + self, request: Request, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> HttpResponse: + if request.method == "GET": + adapter_type = request.GET.get(AdapterKeys.ADAPTER_TYPE) + if ( + adapter_type == AdapterKeys.LLM + or adapter_type == AdapterKeys.EMBEDDING + or adapter_type == AdapterKeys.VECTOR_DB + or adapter_type == AdapterKeys.X2TEXT + ): + json_schema = AdapterProcessor.get_all_supported_adapters( + type=adapter_type + ) + return Response(json_schema, status=status.HTTP_200_OK) + else: + raise InValidType + + def get_adapter_schema( + self, request: Request, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> HttpResponse: + if request.method == "GET": + adapter_name = request.GET.get(AdapterKeys.ID) + if adapter_name is None or adapter_name == "": + raise IdIsMandatory() + json_schema = AdapterProcessor.get_json_schema( + adapter_id=adapter_name + ) + return Response(data=json_schema, status=status.HTTP_200_OK) + + def test(self, request: Request) -> Response: + """Tests the connector against the credentials passed.""" + serializer: AdapterInstanceSerializer = self.get_serializer( + data=request.data + ) + serializer.is_valid(raise_exception=True) + adapter_id = serializer.validated_data.get(AdapterKeys.ADAPTER_ID) + adapter_metadata = serializer.validated_data.get( + AdapterKeys.ADAPTER_METADATA + ) + adapter_metadata[ + AdapterKeys.ADAPTER_TYPE + ] = serializer.validated_data.get(AdapterKeys.ADAPTER_TYPE) + test_result = AdapterProcessor.test_adapter( + adapter_id=adapter_id, adapter_metadata=adapter_metadata + ) + return Response( + {AdapterKeys.IS_VALID: test_result}, + status=status.HTTP_200_OK, + ) + + +class AdapterInstanceViewSet(ModelViewSet): + queryset = AdapterInstance.objects.all() + + serializer_class = AdapterInstanceSerializer + + def get_queryset(self) -> Optional[QuerySet]: + if filter_args := FilterHelper.build_filter_args( + self.request, + constant.ADAPTER_TYPE, + ): + queryset = AdapterInstance.objects.filter( + created_by=self.request.user, **filter_args + ) + else: + queryset = AdapterInstance.objects.filter( + created_by=self.request.user + ) + return queryset + + def create(self, request: Any) -> Response: + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + try: + # Check to see if there is a default configured + # for this adapter_type and for the current user + existing_adapter_default = self.get_existing_defaults( + request.data, request.user + ) + # If there is no default, then make this one as default + if existing_adapter_default is None: + # Update the adapter_instance to is_default=True + serializer.validated_data[AdapterKeys.IS_DEFAULT] = True + + serializer.save() + except IntegrityError: + raise UniqueConstraintViolation( + f"{AdapterKeys.ADAPTER_NAME_EXISTS}" + ) + except Exception as e: + logger.error(f"Error saving adapter to DB: {e}") + raise InternalServiceError + headers = self.get_success_headers(serializer.data) + return Response( + serializer.data, status=status.HTTP_201_CREATED, headers=headers + ) + + def get_existing_defaults( + self, adapter_config: dict[str, Any], user: User + ) -> Optional[AdapterInstance]: + filter_params: dict[str, Any] = {} + adapter_type = adapter_config.get(AdapterKeys.ADAPTER_TYPE) + filter_params["adapter_type"] = adapter_type + filter_params["is_default"] = True + filter_params["created_by"] = user + existing_adapter_default: AdapterInstance = ( + AdapterInstance.objects.filter(**filter_params).first() + ) + + return existing_adapter_default + + +class AdapterDetailViewSet(ModelViewSet): + queryset = AdapterInstance.objects.all() + serializer_class = AdapterDetailSerializer + permission_classes = [IsOwner] + + def destroy( + self, request: Request, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> Response: + adapter_instance: AdapterInstance = self.get_object() + if adapter_instance.is_default: + logger.error("Cannot delete a default adapter") + raise CannotDeleteDefaultAdapter + super().perform_destroy(adapter_instance) + return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/backend/api/__init__.py b/backend/api/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/api/admin.py b/backend/api/admin.py new file mode 100644 index 000000000..37f0837a7 --- /dev/null +++ b/backend/api/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import APIDeployment, APIKey + +admin.site.register([APIDeployment, APIKey]) diff --git a/backend/api/api_deployment_views.py b/backend/api/api_deployment_views.py new file mode 100644 index 000000000..4de36c821 --- /dev/null +++ b/backend/api/api_deployment_views.py @@ -0,0 +1,113 @@ +from typing import Any, Optional + +from api.deployment_helper import DeploymentHelper +from api.exceptions import InvalidAPIRequest +from api.models import APIDeployment +from api.serializers import ( + APIDeploymentListSerializer, + APIDeploymentSerializer, + DeploymentResponseSerializer, + ExecutionRequestSerializer, +) +from django.db.models import QuerySet +from permissions.permission import IsOwner +from rest_framework import serializers, status, views, viewsets +from rest_framework.decorators import action +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.serializers import Serializer +from workflow_manager.workflow.dto import ExecutionResponse + + +class DeploymentExecution(views.APIView): + def initialize_request( + self, request: Request, *args: Any, **kwargs: Any + ) -> Request: + """To remove csrf request for public API. + + Args: + request (Request): _description_ + + Returns: + Request: _description_ + """ + setattr(request, "csrf_processing_done", True) + return super().initialize_request(request, *args, **kwargs) + + @DeploymentHelper.validate_api_key + def post( + self, request: Request, org_name: str, api_name: str, api: APIDeployment + ) -> Response: + file_objs = request.FILES.getlist("files") + serializer = ExecutionRequestSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + timeout = serializer.get_timeout(serializer.validated_data) + + if not file_objs or len(file_objs) == 0: + raise InvalidAPIRequest("File shouldn't be empty") + response = DeploymentHelper.execute_workflow( + organization_name=org_name, + api=api, + file_objs=file_objs, + timeout=timeout, + ) + return Response({"message": response}, status=status.HTTP_200_OK) + + @DeploymentHelper.validate_api_key + def get( + self, request: Request, org_name: str, api_name: str, api: APIDeployment + ) -> Response: + execution_id = request.query_params.get("execution_id") + if not execution_id: + raise InvalidAPIRequest("execution_id shouldn't be empty") + response: ExecutionResponse = DeploymentHelper.get_execution_status( + execution_id=execution_id + ) + return Response( + {"status": response.execution_status, "message": response.result}, + status=status.HTTP_200_OK, + ) + + +class APIDeploymentViewSet(viewsets.ModelViewSet): + permission_classes = [IsOwner] + + def get_queryset(self) -> Optional[QuerySet]: + return APIDeployment.objects.filter(created_by=self.request.user) + + def get_serializer_class(self) -> serializers.Serializer: + if self.action in ["list"]: + return APIDeploymentListSerializer + return APIDeploymentSerializer + + @action(detail=True, methods=["get"]) + def fetch_one(self, request: Request, pk: Optional[str] = None) -> Response: + """Custom action to fetch a single instance.""" + instance = self.get_object() + serializer = self.get_serializer(instance) + return Response(serializer.data) + + def create( + self, request: Request, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> Response: + serializer: Serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + api_key = DeploymentHelper.create_api_key(serializer=serializer) + response_serializer = DeploymentResponseSerializer( + {"api_key": api_key.api_key, **serializer.data} + ) + + headers = self.get_success_headers(serializer.data) + return Response( + response_serializer.data, + status=status.HTTP_201_CREATED, + headers=headers, + ) + + +def get_error_from_serializer(error_details: dict[str, Any]) -> Optional[str]: + error_key = next(iter(error_details)) + # Get the first error message + error_message: str = f"{error_details[error_key][0]} : {error_key}" + return error_message diff --git a/backend/api/api_key_views.py b/backend/api/api_key_views.py new file mode 100644 index 000000000..8f26eab65 --- /dev/null +++ b/backend/api/api_key_views.py @@ -0,0 +1,28 @@ +from api.deployment_helper import DeploymentHelper +from api.exceptions import APINotFound +from api.key_helper import KeyHelper +from api.models import APIKey +from api.serializers import APIKeyListSerializer, APIKeySerializer +from rest_framework import serializers, viewsets +from rest_framework.decorators import action +from rest_framework.request import Request +from rest_framework.response import Response + + +class APIKeyViewSet(viewsets.ModelViewSet): + queryset = APIKey.objects.all() + + def get_serializer_class(self) -> serializers.Serializer: + if self.action in ["api_keys"]: + return APIKeyListSerializer + return APIKeySerializer + + @action(detail=True, methods=["get"]) + def api_keys(self, request: Request, api_id: str) -> Response: + """Custom action to fetch api keys of an api deployment.""" + api = DeploymentHelper.get_api_by_id(api_id=api_id) + if not api: + raise APINotFound() + keys = KeyHelper.list_api_keys_of_api(api_instance=api) + serializer = self.get_serializer(keys, many=True) + return Response(serializer.data) diff --git a/backend/api/apps.py b/backend/api/apps.py new file mode 100644 index 000000000..14b89a829 --- /dev/null +++ b/backend/api/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ApiConfig(AppConfig): + name = "api" diff --git a/backend/api/constants.py b/backend/api/constants.py new file mode 100644 index 000000000..7aa2a4629 --- /dev/null +++ b/backend/api/constants.py @@ -0,0 +1,3 @@ +class ApiExecution: + PATH: str = "deployment/api" + MAXIMUM_TIMEOUT_IN_SEC: int = 300 # 5 minutes diff --git a/backend/api/deployment_helper.py b/backend/api/deployment_helper.py new file mode 100644 index 000000000..d2136990b --- /dev/null +++ b/backend/api/deployment_helper.py @@ -0,0 +1,254 @@ +import logging +import uuid +from functools import wraps +from typing import Any, Optional +from urllib.parse import urlencode + +from api.constants import ApiExecution +from api.exceptions import ( + ApiKeyCreateException, + APINotFound, + Forbidden, + InactiveAPI, + UnauthorizedKey, +) +from api.key_helper import KeyHelper +from api.models import APIDeployment, APIKey +from api.serializers import APIExecutionResponseSerializer +from django.core.files.uploadedfile import UploadedFile +from django.db import connection +from django_tenants.utils import get_tenant_model, tenant_context +from rest_framework import status +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.serializers import Serializer +from rest_framework.utils.serializer_helpers import ReturnDict +from workflow_manager.endpoint.destination import DestinationConnector +from workflow_manager.endpoint.source import SourceConnector +from workflow_manager.workflow.dto import ExecutionResponse +from workflow_manager.workflow.models.workflow import Workflow +from workflow_manager.workflow.workflow_helper import WorkflowHelper + +logger = logging.getLogger(__name__) + + +class DeploymentHelper: + @staticmethod + def validate_api_key(func: Any) -> Any: + """Decorator that validates the API key. + + Sample header: + Authorization: Bearer 123e4567-e89b-12d3-a456-426614174001 + Args: + func (Any): Function to wrap for validation + """ + + @wraps(func) + def wrapper( + self: Any, request: Request, *args: Any, **kwargs: Any + ) -> Any: + """Wrapper to validate the inputs and key. + + Args: + request (Request): Request context + + Raises: + Forbidden: _description_ + APINotFound: _description_ + + Returns: + Any: _description_ + """ + try: + authorization_header = request.headers.get("Authorization") + api_key = None + if authorization_header and authorization_header.startswith( + "Bearer " + ): + api_key = authorization_header.split(" ")[1] + if not api_key: + raise Forbidden("Missing api key") + org_name = kwargs.get("org_name") or request.data.get( + "org_name" + ) + api_name = kwargs.get("api_name") or request.data.get( + "api_name" + ) + if not api_name: + raise Forbidden("Missing api_name") + tenant = get_tenant_model().objects.get(schema_name=org_name) + with tenant_context(tenant): + api_deployment = ( + DeploymentHelper.get_deployment_by_api_name( + api_name=api_name + ) + ) + DeploymentHelper.validate_api( + api_deployment=api_deployment, api_key=api_key + ) + kwargs["api"] = api_deployment + return func(self, request, *args, **kwargs) + except (UnauthorizedKey, InactiveAPI, APINotFound): + raise + except Exception as exception: + logger.error(f"Exception: {exception}") + return Response( + {"error": str(exception)}, status=status.HTTP_403_FORBIDDEN + ) + + return wrapper + + @staticmethod + def validate_api( + api_deployment: Optional[APIDeployment], api_key: str + ) -> None: + """Validating API and API key. + + Args: + api_deployment (Optional[APIDeployment]): _description_ + api_key (str): _description_ + + Raises: + APINotFound: _description_ + InactiveAPI: _description_ + """ + if not api_deployment: + raise APINotFound() + if not api_deployment.is_active: + raise InactiveAPI() + KeyHelper.validate_api_key(api_key=api_key, api_instance=api_deployment) + + @staticmethod + def validate_and_get_workflow(workflow_id: str) -> Workflow: + """Validate that the specified workflow_id exists in the Workflow + model.""" + return WorkflowHelper.get_workflow_by_id(workflow_id) + + @staticmethod + def get_api_by_id(api_id: str) -> Optional[APIDeployment]: + try: + api_deployment: APIDeployment = APIDeployment.objects.get(pk=api_id) + return api_deployment + except APIDeployment.DoesNotExist: + return None + + @staticmethod + def construct_complete_endpoint(api_name: str) -> str: + """Constructs the complete API endpoint by appending organization + schema, endpoint path, and Django app backend URL. + + Parameters: + - endpoint (str): The endpoint path to be appended to the complete URL. + + Returns: + - str: The complete API endpoint URL. + """ + org_schema = connection.get_tenant().schema_name + return f"{ApiExecution.PATH}/{org_schema}/{api_name}/" + + @staticmethod + def construct_status_endpoint(api_endpoint: str, execution_id: str) -> str: + """Construct a complete status endpoint URL by appending the + execution_id as a query parameter. + + Args: + api_endpoint (str): The base API endpoint. + execution_id (str): The execution ID to be included as + a query parameter. + + Returns: + str: The complete status endpoint URL. + """ + query_parameters = urlencode({"execution_id": execution_id}) + complete_endpoint = f"{api_endpoint}?{query_parameters}" + return complete_endpoint + + @staticmethod + def get_deployment_by_api_name( + api_name: str, + ) -> Optional[APIDeployment]: + """Get and return the APIDeployment object by api_name.""" + try: + api: APIDeployment = APIDeployment.objects.get(api_name=api_name) + return api + except APIDeployment.DoesNotExist: + return None + + @staticmethod + def create_api_key(serializer: Serializer) -> APIKey: + """To make API key for an API. + + Args: + serializer (Serializer): Request serializer + + Raises: + ApiKeyCreateException: Exception + """ + api_deployment: APIDeployment = serializer.instance + try: + api_key: APIKey = KeyHelper.create_api_key(api_deployment) + return api_key + except Exception as error: + logger.error(f"Error while creating API key error: {str(error)}") + api_deployment.delete() + logger.info("Deleted the deployment instance") + raise ApiKeyCreateException() + + @staticmethod + def execute_workflow( + organization_name: str, + api: APIDeployment, + file_objs: list[UploadedFile], + timeout: int, + ) -> ReturnDict: + """Execute workflow by api. + + Args: + organization_name (str): organization name + api (APIDeployment): api model object + file_obj (UploadedFile): input file + + Returns: + ReturnDict: execution status/ result + """ + workflow_id = api.workflow.id + pipeline_id = api.id + execution_id = str(uuid.uuid4()) + + hash_values_of_files = SourceConnector.add_input_file_to_api_storage( + workflow_id=workflow_id, + execution_id=execution_id, + file_objs=file_objs, + ) + try: + result = WorkflowHelper.execute_workflow_async( + workflow_id=workflow_id, + pipeline_id=pipeline_id, + hash_values_of_files=hash_values_of_files, + timeout=timeout, + execution_id=execution_id, + ) + result.status_api = DeploymentHelper.construct_status_endpoint( + api_endpoint=api.api_endpoint, execution_id=execution_id + ) + except Exception: + DestinationConnector.delete_api_storage_dir( + workflow_id=workflow_id, execution_id=execution_id + ) + raise + return APIExecutionResponseSerializer(result).data + + @staticmethod + def get_execution_status(execution_id: str) -> ExecutionResponse: + """Current status of api execution. + + Args: + execution_id (str): execution id + + Returns: + ReturnDict: status/result of execution + """ + execution_response: ExecutionResponse = ( + WorkflowHelper.get_status_of_async_task(execution_id=execution_id) + ) + return execution_response diff --git a/backend/api/exceptions.py b/backend/api/exceptions.py new file mode 100644 index 000000000..6d1b65ac0 --- /dev/null +++ b/backend/api/exceptions.py @@ -0,0 +1,94 @@ +from typing import Optional + +from rest_framework.exceptions import APIException + + +class MandatoryWorkflowId(APIException): + status_code = 400 + default_detail = "Workflow ID is mandatory" + + +class ApiKeyCreateException(APIException): + status_code = 500 + default_detail = "Exception while create API key" + + def __init__( + self, detail: Optional[str] = None, code: Optional[int] = None + ): + if detail is not None: + self.detail = detail + if code is not None: + self.code = code + super().__init__(detail, code) + + +class Forbidden(APIException): + status_code = 403 + default_detail = ( + "User is forbidden from performing this action. Please contact admin" + ) + + def __init__( + self, detail: Optional[str] = None, code: Optional[int] = None + ): + if detail is not None: + self.detail = detail + if code is not None: + self.code = code + super().__init__(detail, code) + + +class APINotFound(APIException): + status_code = 404 + default_detail = "Api not found" + + def __init__( + self, detail: Optional[str] = None, code: Optional[int] = None + ): + if detail is not None: + self.detail = detail + if code is not None: + self.code = code + super().__init__(detail, code) + + +class InvalidAPIRequest(APIException): + status_code = 400 + default_detail = "Bad request" + + def __init__( + self, detail: Optional[str] = None, code: Optional[int] = None + ): + if detail is not None: + self.detail = detail + if code is not None: + self.code = code + super().__init__(detail, code) + + +class InactiveAPI(APIException): + status_code = 404 + default_detail = "API not found or Inactive" + + def __init__( + self, detail: Optional[str] = None, code: Optional[int] = None + ): + if detail is not None: + self.detail = detail + if code is not None: + self.code = code + super().__init__(detail, code) + + +class UnauthorizedKey(APIException): + status_code = 401 + default_detail = "Unauthorized" + + def __init__( + self, detail: Optional[str] = None, code: Optional[int] = None + ): + if detail is not None: + self.detail = detail + if code is not None: + self.code = code + super().__init__(detail, code) diff --git a/backend/api/key_helper.py b/backend/api/key_helper.py new file mode 100644 index 000000000..d65345c15 --- /dev/null +++ b/backend/api/key_helper.py @@ -0,0 +1,72 @@ +import logging + +from api.exceptions import Forbidden, UnauthorizedKey +from api.models import APIDeployment, APIKey +from api.serializers import APIKeySerializer +from workflow_manager.workflow.workflow_helper import WorkflowHelper + +logger = logging.getLogger(__name__) + + +class KeyHelper: + @staticmethod + def validate_api_key(api_key: str, api_instance: APIDeployment) -> None: + """Validate api key. + + Args: + api_key (str): api key from request + api_instance (APIDeployment): api deployment instance + + Raises: + Forbidden: _description_ + """ + try: + api_key_instance: APIKey = APIKey.objects.get(api_key=api_key) + if not KeyHelper.has_access(api_key_instance, api_instance): + raise UnauthorizedKey() + except APIKey.DoesNotExist: + raise UnauthorizedKey() + except APIDeployment.DoesNotExist: + raise Forbidden("API not found.") + + @staticmethod + def list_api_keys_of_api(api_instance: APIDeployment) -> list[APIKey]: + api_keys: list[APIKey] = APIKey.objects.filter(api=api_instance).all() + return api_keys + + @staticmethod + def has_access(api_key: APIKey, api_instance: APIDeployment) -> bool: + """Check if the provided API key has access to the specified API + instance. + + Args: + api_key (APIKey): api key associated with the api + api_instance (APIDeployment): api model + + Returns: + bool: True if allowed to execute, False otherwise + """ + if not api_key.is_active: + return False + if isinstance(api_key.api, APIDeployment): + return api_key.api == api_instance + return False + + @staticmethod + def validate_workflow_exists(workflow_id: str) -> None: + """Validate that the specified workflow_id exists in the Workflow + model.""" + WorkflowHelper.get_workflow_by_id(workflow_id) + + @staticmethod + def create_api_key(deployment: APIDeployment) -> APIKey: + """Create an APIKey entity with the data from the provided + APIDeployment instance.""" + # Create an instance of the APIKey model + api_key_serializer = APIKeySerializer( + data={"api": deployment.id, "description": "Initial Access Key"}, + context={"deployment": deployment}, + ) + api_key_serializer.is_valid(raise_exception=True) + api_key: APIKey = api_key_serializer.save() + return api_key diff --git a/backend/api/migrations/0001_initial.py b/backend/api/migrations/0001_initial.py new file mode 100644 index 000000000..8ee7d8211 --- /dev/null +++ b/backend/api/migrations/0001_initial.py @@ -0,0 +1,185 @@ +# Generated by Django 4.2.1 on 2024-01-23 11:18 + +import uuid + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("workflow", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="APIDeployment", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "display_name", + models.CharField( + db_comment="User-given display name for the API.", + default="default api", + max_length=30, + unique=True, + ), + ), + ( + "description", + models.CharField( + blank=True, + db_comment="User-given description for the API.", + default="", + max_length=255, + ), + ), + ( + "is_active", + models.BooleanField( + db_comment="Flag indicating whether the API is active or not.", + default=True, + ), + ), + ( + "api_endpoint", + models.CharField( + db_comment="URL endpoint for the API deployment.", + editable=False, + max_length=255, + unique=True, + ), + ), + ( + "api_name", + models.CharField( + db_comment="Short name for the API deployment.", + default="default", + max_length=30, + unique=True, + ), + ), + ( + "created_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="api_created_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="api_modified_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "workflow", + models.ForeignKey( + db_comment="Foreign key reference to the Workflow model.", + on_delete=django.db.models.deletion.CASCADE, + to="workflow.workflow", + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="APIKey", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "id", + models.UUIDField( + db_comment="Unique identifier for the API key.", + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "api_key", + models.UUIDField( + db_comment="Actual key UUID.", + default=uuid.uuid4, + editable=False, + unique=True, + ), + ), + ( + "description", + models.CharField( + db_comment="Description of the API key.", + max_length=255, + null=True, + ), + ), + ( + "is_active", + models.BooleanField( + db_comment="Flag indicating whether the API key is active or not.", + default=True, + ), + ), + ( + "api", + models.ForeignKey( + db_comment="Foreign key reference to the APIDeployment model.", + on_delete=django.db.models.deletion.CASCADE, + to="api.apideployment", + ), + ), + ( + "created_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="api_key_created_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="api_key_modified_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/backend/api/migrations/__init__.py b/backend/api/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/api/models.py b/backend/api/models.py new file mode 100644 index 000000000..ac07ec74f --- /dev/null +++ b/backend/api/models.py @@ -0,0 +1,141 @@ +import uuid +from typing import Any + +from account.models import User +from api.constants import ApiExecution +from django.db import connection, models +from utils.models.base_model import BaseModel +from workflow_manager.workflow.models.workflow import Workflow + +API_NAME_MAX_LENGTH = 30 +DESCRIPTION_MAX_LENGTH = 255 +API_ENDPOINT_MAX_LENGTH = 255 + + +class APIDeployment(BaseModel): + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + display_name = models.CharField( + max_length=API_NAME_MAX_LENGTH, + unique=True, + default="default api", + db_comment="User-given display name for the API.", + ) + description = models.CharField( + max_length=DESCRIPTION_MAX_LENGTH, + blank=True, + default="", + db_comment="User-given description for the API.", + ) + workflow = models.ForeignKey( + Workflow, + on_delete=models.CASCADE, + db_comment="Foreign key reference to the Workflow model.", + ) + is_active = models.BooleanField( + default=True, + db_comment="Flag indicating whether the API is active or not.", + ) + api_endpoint = models.CharField( + max_length=API_ENDPOINT_MAX_LENGTH, + unique=True, + editable=False, + db_comment="URL endpoint for the API deployment.", + ) + api_name = models.CharField( + max_length=API_NAME_MAX_LENGTH, + unique=True, + default="default", + db_comment="Short name for the API deployment.", + ) + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="api_created_by", + null=True, + blank=True, + editable=False, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="api_modified_by", + null=True, + blank=True, + editable=False, + ) + + def __str__(self) -> str: + return f"{self.id} - {self.display_name}" + + def save(self, *args: Any, **kwargs: Any) -> None: + """Save hook to update api_endpoint. + + Custom save hook for updating the 'api_endpoint' based on + 'api_name'. If the instance is being updated, it checks for + changes in 'api_name' and adjusts 'api_endpoint' + accordingly. If the instance is new, 'api_endpoint' is set + based on 'api_name' and the current database schema. + """ + if self.pk is not None: + try: + original = APIDeployment.objects.get(pk=self.pk) + if original.api_name != self.api_name: + org_schema = connection.get_tenant().schema_name + self.api_endpoint = ( + f"{ApiExecution.PATH}/{org_schema}/{self.api_name}/" + ) + except APIDeployment.DoesNotExist: + org_schema = connection.get_tenant().schema_name + + self.api_endpoint = ( + f"{ApiExecution.PATH}/{org_schema}/{self.api_name}/" + ) + super().save(*args, **kwargs) + + +class APIKey(BaseModel): + id = models.UUIDField( + primary_key=True, + editable=False, + default=uuid.uuid4, + db_comment="Unique identifier for the API key.", + ) + api_key = models.UUIDField( + default=uuid.uuid4, + editable=False, + unique=True, + db_comment="Actual key UUID.", + ) + api = models.ForeignKey( + APIDeployment, + on_delete=models.CASCADE, + db_comment="Foreign key reference to the APIDeployment model.", + ) + description = models.CharField( + max_length=DESCRIPTION_MAX_LENGTH, + null=True, + db_comment="Description of the API key.", + ) + is_active = models.BooleanField( + default=True, + db_comment="Flag indicating whether the API key is active or not.", + ) + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="api_key_created_by", + null=True, + blank=True, + editable=False, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="api_key_modified_by", + null=True, + blank=True, + editable=False, + ) + + def __str__(self) -> str: + return f"{self.api.api_name} - {self.id} - {self.api_key}" diff --git a/backend/api/serializers.py b/backend/api/serializers.py new file mode 100644 index 000000000..ece1e6de9 --- /dev/null +++ b/backend/api/serializers.py @@ -0,0 +1,124 @@ +from collections import OrderedDict +from typing import Any, Union + +from api.constants import ApiExecution +from api.models import APIDeployment, APIKey +from backend.serializers import AuditSerializer +from django.core.validators import RegexValidator +from rest_framework.serializers import ( + CharField, + IntegerField, + JSONField, + ModelSerializer, + Serializer, + ValidationError, +) + + +class APIDeploymentSerializer(AuditSerializer): + class Meta: + model = APIDeployment + fields = "__all__" + + def validate_api_name(self, value: str) -> str: + api_name_validator = RegexValidator( + regex=r"^[a-zA-Z0-9_-]+$", + message="Only letters, numbers, hyphen and \ + underscores are allowed.", + code="invalid_api_name", + ) + api_name_validator(value) + return value + + +class APIKeySerializer(AuditSerializer): + class Meta: + model = APIKey + fields = "__all__" + + def to_representation(self, instance: APIKey) -> OrderedDict[str, Any]: + """Override the to_representation method to include additional + context.""" + context = self.context.get("context", {}) + deployment: APIDeployment = context.get("deployment") + representation: OrderedDict[str, Any] = super().to_representation( + instance + ) + if deployment: + representation["api"] = deployment.id + representation["description"] = f"API Key for {deployment.name}" + representation["is_active"] = True + + return representation + + +class ExecutionRequestSerializer(Serializer): + """Execution request serializer + timeout: 0: maximum value of timeout, -1: async execution + """ + + timeout = IntegerField( + min_value=-1, max_value=ApiExecution.MAXIMUM_TIMEOUT_IN_SEC, default=-1 + ) + + def validate_timeout(self, value: Any) -> int: + if not isinstance(value, int): + raise ValidationError("timeout must be a integer.") + if value == 0: + value = ApiExecution.MAXIMUM_TIMEOUT_IN_SEC + return value + + def get_timeout(self, validated_data: dict[str, Union[int, None]]) -> int: + value = validated_data.get("timeout", -1) + if not isinstance(value, int): + raise ValidationError("timeout must be a integer.") + return value + + +class APIDeploymentListSerializer(ModelSerializer): + workflow_name = CharField(source="workflow.workflow_name", read_only=True) + + class Meta: + model = APIDeployment + fields = [ + "id", + "workflow", + "workflow_name", + "display_name", + "description", + "is_active", + "api_endpoint", + "api_name", + "created_by", + ] + + +class APIKeyListSerializer(ModelSerializer): + class Meta: + model = APIKey + fields = [ + "id", + "created_at", + "modified_at", + "api_key", + "is_active", + "description", + "api", + ] + + +class DeploymentResponseSerializer(Serializer): + is_active = CharField() + id = CharField() + api_key = CharField() + api_endpoint = CharField() + display_name = CharField() + description = CharField() + api_name = CharField() + + +class APIExecutionResponseSerializer(Serializer): + execution_status = CharField() + status_api = CharField() + error = CharField() + result = JSONField() diff --git a/backend/api/tests.py b/backend/api/tests.py new file mode 100644 index 000000000..a39b155ac --- /dev/null +++ b/backend/api/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/backend/api/urls.py b/backend/api/urls.py new file mode 100644 index 000000000..2b149bf48 --- /dev/null +++ b/backend/api/urls.py @@ -0,0 +1,52 @@ +from api.api_deployment_views import APIDeploymentViewSet, DeploymentExecution +from api.api_key_views import APIKeyViewSet +from django.urls import path, re_path +from rest_framework.urlpatterns import format_suffix_patterns + +deployment = APIDeploymentViewSet.as_view( + { + "get": APIDeploymentViewSet.list.__name__, + "post": APIDeploymentViewSet.create.__name__, + } +) +deployment_details = APIDeploymentViewSet.as_view( + { + "get": APIDeploymentViewSet.retrieve.__name__, + "put": APIDeploymentViewSet.update.__name__, + "patch": APIDeploymentViewSet.partial_update.__name__, + "delete": APIDeploymentViewSet.destroy.__name__, + } +) +execute = DeploymentExecution.as_view() + +key_details = APIKeyViewSet.as_view( + { + "get": APIKeyViewSet.retrieve.__name__, + "put": APIKeyViewSet.update.__name__, + "delete": APIKeyViewSet.destroy.__name__, + } +) +api_key = APIKeyViewSet.as_view( + { + "get": APIKeyViewSet.api_keys.__name__, + "post": APIKeyViewSet.create.__name__, + } +) + +urlpatterns = format_suffix_patterns( + [ + path("deployment/", deployment, name="api_deployment"), + path( + "deployment//", + deployment_details, + name="api_deployment_details", + ), + re_path( + r"^api/(?P[\w-]+)/(?P[\w-]+)/?$", + execute, + name="api_deployment_execution", + ), + path("keys//", key_details, name="key_details"), + path("keys/api//", api_key, name="api_key"), + ] +) diff --git a/backend/apps/__init__.py b/backend/apps/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/apps/constants.py b/backend/apps/constants.py new file mode 100644 index 000000000..67be60df6 --- /dev/null +++ b/backend/apps/constants.py @@ -0,0 +1,4 @@ +class AppConstants: + """Constants for Apps.""" + + \ No newline at end of file diff --git a/backend/apps/exceptions.py b/backend/apps/exceptions.py new file mode 100644 index 000000000..7836889b2 --- /dev/null +++ b/backend/apps/exceptions.py @@ -0,0 +1,6 @@ +from rest_framework.exceptions import APIException + + +class FetchAppListFailed(APIException): + status_code = 400 + default_detail = "Failed to fetch App list." \ No newline at end of file diff --git a/backend/apps/urls.py b/backend/apps/urls.py new file mode 100644 index 000000000..918cedca7 --- /dev/null +++ b/backend/apps/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from apps import views +from rest_framework.urlpatterns import format_suffix_patterns + +urlpatterns = format_suffix_patterns( + [ + path("app/", views.get_app_list, name="app-list"), + ] +) diff --git a/backend/apps/views.py b/backend/apps/views.py new file mode 100644 index 000000000..944987319 --- /dev/null +++ b/backend/apps/views.py @@ -0,0 +1,22 @@ +import logging + +from apps.exceptions import FetchAppListFailed +from rest_framework import status +from rest_framework.decorators import api_view +from rest_framework.request import Request +from rest_framework.response import Response + +logger = logging.getLogger(__name__) + + +@api_view(("GET",)) +def get_app_list(request: Request) -> Response: + """API to fetch List of Apps.""" + if request.method == "GET": + try: + return Response(data=[], status=status.HTTP_200_OK) + # Refactored dated: 19/12/2023 + # ( Removed -> backend/apps/app_processor.py ) + except Exception as exe: + logger.error(f"Error occured while fetching app list {exe}") + raise FetchAppListFailed() diff --git a/backend/backend/__init__.py b/backend/backend/__init__.py new file mode 100644 index 000000000..370372af0 --- /dev/null +++ b/backend/backend/__init__.py @@ -0,0 +1,3 @@ +from .celery import app as celery_app + +__all__ = ["celery_app"] diff --git a/backend/backend/asgi.py b/backend/backend/asgi.py new file mode 100644 index 000000000..07774528a --- /dev/null +++ b/backend/backend/asgi.py @@ -0,0 +1,20 @@ +"""ASGI config for backend project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application +from dotenv import load_dotenv + +load_dotenv() +os.environ.setdefault( + "DJANGO_SETTINGS_MODULE", + os.environ.get("DJANGO_SETTINGS_MODULE", "backend.settings.dev"), +) + +application = get_asgi_application() diff --git a/backend/backend/celery.py b/backend/backend/celery.py new file mode 100644 index 000000000..1c790f671 --- /dev/null +++ b/backend/backend/celery.py @@ -0,0 +1,29 @@ +"""This module contains the Celery configuration for the backend +project.""" + +import os + +from celery import Celery +from django.conf import settings + +# Set the default Django settings module for the 'celery' program. +os.environ.setdefault( + "DJANGO_SETTINGS_MODULE", + os.environ.get("DJANGO_SETTINGS_MODULE", "backend.settings.dev"), +) + +# Create a Celery instance. Default time zone is UTC. +app = Celery("backend") + +# Use Redis as the message broker. +app.conf.broker_url = settings.CELERY_BROKER_URL +app.conf.result_backend = settings.CELERY_RESULT_BACKEND + +# Load task modules from all registered Django app configs. +app.config_from_object("django.conf:settings", namespace="CELERY") + +# Autodiscover tasks in all installed apps. +app.autodiscover_tasks() + +# Use the Django-Celery-Beat scheduler. +app.conf.beat_scheduler = "django_celery_beat.schedulers:DatabaseScheduler" diff --git a/backend/backend/constants.py b/backend/backend/constants.py new file mode 100644 index 000000000..6e2c1ceaf --- /dev/null +++ b/backend/backend/constants.py @@ -0,0 +1,30 @@ +class RequestKey: + """Commonly used keys in requests/repsonses.""" + + REQUEST = "request" + PROJECT = "project" + WORKFLOW = "workflow" + CREATED_BY = "created_by" + MODIFIED_BY = "modified_by" + MODIFIED_AT = "modified_at" + + +class FieldLengthConstants: + """Used to determine length of fields in a model.""" + + ORG_NAME_SIZE = 64 + CRON_LENGTH = 256 + UUID_LENGTH = 36 + # Not to be confused with a connector instance + CONNECTOR_ID_LENGTH = 128 + ADAPTER_ID_LENGTH = 128 + + +class RequestHeader: + """Request header constants.""" + + X_API_KEY = "X-API-KEY" + + +class UrlPathConstants: + PROMPT_STUDIO = "prompt-studio/" diff --git a/backend/backend/exceptions.py b/backend/backend/exceptions.py new file mode 100644 index 000000000..f95597670 --- /dev/null +++ b/backend/backend/exceptions.py @@ -0,0 +1,36 @@ +from typing import Any, Optional + +from rest_framework.exceptions import APIException +from rest_framework.response import Response +from rest_framework.views import exception_handler +from unstract.connectors.exceptions import ConnectorBaseException + + +class UnstractBaseException(APIException): + default_detail = "Error occurred" + + def __init__( + self, + detail: Optional[str] = None, + core_err: Optional[ConnectorBaseException] = None, + **kwargs: Any, + ) -> None: + if detail is None: + detail = self.default_detail + if core_err and core_err.user_message: + detail = core_err.user_message + super().__init__(detail=detail, **kwargs) + self._core_err = core_err + + +class LLMHelperError(Exception): + pass + + +def custom_exception_handler(exc, context) -> Response: # type: ignore + response = exception_handler(exc, context) + + if response is not None: + response.data["status_code"] = response.status_code + + return response diff --git a/backend/backend/flowerconfig.py b/backend/backend/flowerconfig.py new file mode 100644 index 000000000..1d25d6458 --- /dev/null +++ b/backend/backend/flowerconfig.py @@ -0,0 +1,15 @@ +# Flower is a real-time web based monitor and administration tool +# for Celery. It’s under active development, +# but is already an essential tool. +from django.conf import settings + +# Broker URL +BROKER_URL = settings.CELERY_BROKER_URL + +# Flower web port +PORT = 5555 + +# Enable basic authentication (when required) +# basic_auth = { +# 'username': 'password' +# } diff --git a/backend/backend/public_urls.py b/backend/backend/public_urls.py new file mode 100644 index 000000000..dabd361b7 --- /dev/null +++ b/backend/backend/public_urls.py @@ -0,0 +1,40 @@ +"""URL configuration for backend project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/4.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" + +from account.admin import admin +from django.conf import settings +from django.conf.urls import * # noqa: F401, F403 +from django.urls import include, path + +path_prefix = settings.PATH_PREFIX +api_path_prefix = settings.API_DEPLOYMENT_PATH_PREFIX + +urlpatterns = [ + path(f"{path_prefix}/", include("account.urls")), + # Admin URLs + path(f"{path_prefix}/admin/doc/", include("django.contrib.admindocs.urls")), + path(f"{path_prefix}/admin/", admin.site.urls), + # Connector OAuth + path(f"{path_prefix}/", include("connector_auth.urls")), + # Docs + path(f"{path_prefix}/", include("docs.urls")), + # Socket.io + path(f"{path_prefix}/", include("log_events.urls")), + # API deployment + path(f"{api_path_prefix}/", include("api.urls")), + # Feature flags + path(f"{path_prefix}/flags/", include("feature_flag.urls")), +] diff --git a/backend/backend/serializers.py b/backend/backend/serializers.py new file mode 100644 index 000000000..151a334d9 --- /dev/null +++ b/backend/backend/serializers.py @@ -0,0 +1,23 @@ +from typing import Any + +from backend.constants import RequestKey +from rest_framework.serializers import ModelSerializer + + +class AuditSerializer(ModelSerializer): + def create(self, validated_data: dict[str, Any]) -> Any: + if self.context.get(RequestKey.REQUEST): + validated_data[RequestKey.CREATED_BY] = self.context.get( + RequestKey.REQUEST + ).user + validated_data[RequestKey.MODIFIED_BY] = self.context.get( + RequestKey.REQUEST + ).user + return super().create(validated_data) + + def update(self, instance: Any, validated_data: dict[str, Any]) -> Any: + if self.context.get(RequestKey.REQUEST): + validated_data[RequestKey.MODIFIED_BY] = self.context.get( + RequestKey.REQUEST + ).user + return super().update(instance, validated_data) diff --git a/backend/backend/settings/__init__.py b/backend/backend/settings/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/backend/settings/base.py b/backend/backend/settings/base.py new file mode 100644 index 000000000..e43bfbeac --- /dev/null +++ b/backend/backend/settings/base.py @@ -0,0 +1,458 @@ +"""Django settings for backend project. + +Generated by 'django-admin startproject' using Django 4.2.1. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.2/ref/settings/ +""" + +import os +from pathlib import Path +from typing import Optional + +from dotenv import find_dotenv, load_dotenv + +missing_settings = [] + + +def get_required_setting( + setting_key: str, default: Optional[str] = None +) -> Optional[str]: + """Get the value of an environment variable specified by the given key. Add + missing keys to `missing_settings` so that exception can be raised at the + end. + + Args: + key (str): The key of the environment variable + default (Optional[str], optional): Default value to return incase of + env not found. Defaults to None. + + Returns: + Optional[str]: The value of the environment variable if found, + otherwise the default value. + """ + data = os.environ.get(setting_key, default) + if not data: + missing_settings.append(setting_key) + return data + + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "verbose": { + "format": "[%(asctime)s] %(levelname)s %(name)s: %(message)s", + "datefmt": "%d/%b/%Y %H:%M:%S", + }, + "simple": { + "format": "{levelname} {message}", + "style": "{", + }, + }, + "handlers": { + "console": { + "level": "INFO", # Set the desired logging level here + "class": "logging.StreamHandler", + "formatter": "verbose", + }, + }, + "root": { + "handlers": ["console"], + "level": "INFO", # Set the desired logging level here as well + }, +} + + +ENV_FILE = find_dotenv() +if ENV_FILE: + load_dotenv(ENV_FILE) + +# Loading environment variables + +WORKFLOW_ACTION_EXPIRATION_TIME_IN_SECOND = os.environ.get( + "WORKFLOW_ACTION_EXPIRATION_TIME_IN_SECOND", 10800 +) +WEB_APP_ORIGIN_URL = os.environ.get( + "WEB_APP_ORIGIN_URL", "http://localhost:3000" +) + +LOGIN_NEXT_URL = os.environ.get("LOGIN_NEXT_URL", "http://localhost:3000/org") +LANDING_URL = os.environ.get("LANDING_URL", "http://localhost:3000/landing") +ERROR_URL = os.environ.get("ERROR_URL", "http://localhost:3000/error") + +DJANGO_APP_BACKEND_URL = os.environ.get( + "DJANGO_APP_BACKEND_URL", "http://localhost:8000" +) +INTERNAL_SERVICE_API_KEY = os.environ.get("INTERNAL_SERVICE_API_KEY") + +GOOGLE_STORAGE_ACCESS_KEY_ID = os.environ.get("GOOGLE_STORAGE_ACCESS_KEY_ID") +GOOGLE_STORAGE_SECRET_ACCESS_KEY = os.environ.get( + "GOOGLE_STORAGE_SECRET_ACCESS_KEY" +) +UNSTRACT_FREE_STORAGE_BUCKET_NAME = os.environ.get( + "UNSTRACT_FREE_STORAGE_BUCKET_NAME", "pandora-user-storage" +) +GOOGLE_STORAGE_BASE_URL = os.environ.get("GOOGLE_STORAGE_BASE_URL") +REDIS_USER = os.environ.get("REDIS_USER", "default") +REDIS_PASSWORD = os.environ.get("REDIS_PASSWORD", "") +REDIS_HOST = os.environ.get("REDIS_HOST", "localhost") +REDIS_PORT = os.environ.get("REDIS_PORT", "6379") +REDIS_DB = os.environ.get("REDIS_DB", "") +SESSION_EXPIRATION_TIME_IN_SECOND = os.environ.get( + "SESSION_EXPIRATION_TIME_IN_SECOND", 3600 +) + +PATH_PREFIX = os.environ.get("PATH_PREFIX", "api/v1").strip("/") +API_DEPLOYMENT_PATH_PREFIX = os.environ.get( + "API_DEPLOYMENT_PATH_PREFIX", "deployment" +).strip("/") + +DB_NAME = os.environ.get("DB_NAME", "unstract_db") +DB_USER = os.environ.get("DB_USER", "unstract_dev") +DB_HOST = os.environ.get("DB_HOST", "backend-db-1") +DB_PASSWORD = os.environ.get("DB_PASSWORD", "unstract_pass") +DB_PORT = os.environ.get("DB_PORT", 5432) + +DEFAULT_ORGANIZATION = "default_org" +FLIPT_BASE_URL = os.environ.get("FLIPT_BASE_URL", "http://localhost:9005") +PLATFORM_HOST = os.environ.get("PLATFORM_SERVICE_HOST", "http://localhost") +PLATFORM_PORT = os.environ.get("PLATFORM_SERVICE_PORT", 3001) +PROMPT_HOST = os.environ.get("PROMPT_HOST", "http://localhost") +PROMPT_PORT = os.environ.get("PROMPT_PORT", 3003) +PROMPT_STUDIO_FILE_PATH = os.environ.get( + "PROMPT_STUDIO_FILE_PATH", "/app/prompt-studio-data" +) +X2TEXT_HOST = os.environ.get("X2TEXT_HOST", "http://localhost") +X2TEXT_PORT = os.environ.get("X2TEXT_PORT", 3004) +STRUCTURE_TOOL_IMAGE_URL = get_required_setting("STRUCTURE_TOOL_IMAGE_URL") +STRUCTURE_TOOL_IMAGE_NAME = get_required_setting("STRUCTURE_TOOL_IMAGE_NAME") +STRUCTURE_TOOL_IMAGE_TAG = get_required_setting("STRUCTURE_TOOL_IMAGE_TAG") +WORKFLOW_DATA_DIR = os.environ.get("WORKFLOW_DATA_DIR") +API_STORAGE_DIR = os.environ.get("API_STORAGE_DIR") +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = get_required_setting("DJANGO_SECRET_KEY") + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ["*"] +CSRF_TRUSTED_ORIGINS = [WEB_APP_ORIGIN_URL] +CORS_ALLOW_ALL_ORIGINS = False +SESSION_COOKIE_AGE = 86400 + + +# Application definition +SHARED_APPS = ( + # Multitenancy + "django_tenants", + "corsheaders", + # For the organization model + "account", + # Django apps should go below this line + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "django.contrib.admindocs", + # Third party apps should go below this line, + "rest_framework", + # Connector OAuth + "connector_auth", + "social_django", + # Doc generator + "drf_yasg", + "docs", + # Plugins + "plugins", + "log_events", + "feature_flag", + "django_celery_beat", +) + +TENANT_APPS = ( + # your tenant-specific apps + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "tenant_account", + "project", + "prompt", + "connector", + "adapter_processor", + "file_management", + "workflow_manager.endpoint", + "workflow_manager.workflow", + "tool_instance", + "pipeline", + "cron_expression_generator", + "platform_settings", + "api", + "prompt_studio.prompt_profile_manager", + "prompt_studio.prompt_studio", + "prompt_studio.prompt_studio_core", + "prompt_studio.prompt_studio_registry", + "prompt_studio.prompt_studio_output_manager", +) + +INSTALLED_APPS = list(SHARED_APPS) + [ + app for app in TENANT_APPS if app not in SHARED_APPS +] +DEFAULT_MODEL_BACKEND = "django.contrib.auth.backends.ModelBackend" +GOOGLE_MODEL_BACKEND = "social_core.backends.google.GoogleOAuth2" + +AUTHENTICATION_BACKENDS = ( + DEFAULT_MODEL_BACKEND, + GOOGLE_MODEL_BACKEND, +) + +TENANT_MODEL = "account.Organization" +TENANT_DOMAIN_MODEL = "account.Domain" +AUTH_USER_MODEL = "account.User" +PUBLIC_ORG_ID = "public" + +MIDDLEWARE = [ + "corsheaders.middleware.CorsMiddleware", + "django_tenants.middleware.TenantSubfolderMiddleware", + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.middleware.common.CommonMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "account.custom_auth_middleware.CustomAuthMiddleware", + "middleware.exception.ExceptionLoggingMiddleware", + "social_django.middleware.SocialAuthExceptionMiddleware", +] + +PUBLIC_SCHEMA_URLCONF = "backend.public_urls" +ROOT_URLCONF = "backend.urls" +TENANT_SUBFOLDER_PREFIX = f"/{PATH_PREFIX}/unstract" +SHOW_PUBLIC_IF_NO_TENANT_FOUND = True + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +WSGI_APPLICATION = "backend.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django_tenants.postgresql_backend", + "NAME": f"{DB_NAME}", + "USER": f"{DB_USER}", + "HOST": f"{DB_HOST}", + "PASSWORD": f"{DB_PASSWORD}", + "PORT": f"{DB_PORT}", + "ATOMIC_REQUESTS": True, + } +} + +DATABASE_ROUTERS = ("django_tenants.routers.TenantSyncRouter",) + +CACHES = { + "default": { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": f"redis://{REDIS_HOST}:{REDIS_PORT}", + "OPTIONS": { + "CLIENT_CLASS": "django_redis.client.DefaultClient", + "SERIALIZER": "django_redis.serializers.json.JSONSerializer", + "DB": REDIS_DB, + "USERNAME": REDIS_USER, + "PASSWORD": REDIS_PASSWORD, + }, + "KEY_FUNCTION": "account.cache_service.custom_key_function", + } +} + +RQ_QUEUES = { + "default": {"USE_REDIS_CACHE": "default"}, +} + +# Used for asynchronous/Queued execution +# Celery based scheduler +CELERY_BROKER_URL = f"redis://{REDIS_HOST}:{REDIS_PORT}" + +# CELERY_RESULT_BACKEND = f"redis://{REDIS_HOST}:{REDIS_PORT}/1" +# Postgres as result backend +CELERY_RESULT_BACKEND = ( + f"db+postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}" +) +CELERY_ACCEPT_CONTENT = ["json"] +CELERY_TASK_SERIALIZER = "json" +CELERY_RESULT_SERIALIZER = "json" +CELERY_TIMEZONE = "UTC" +CELERY_TASK_MAX_RETRIES = 3 +CELERY_TASK_RETRY_BACKOFF = 60 # Time in seconds before retrying the task + +# Feature Flag +FEATURE_FLAG_SERVICE_URL = { + "evaluate": f"{FLIPT_BASE_URL}/api/v1/flags/evaluate/" +} + +SCHEDULER_KWARGS = { + "coalesce": True, + "misfire_grace_time": 300, + "max_instances": 1, + "replace_existing": True, +} + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation." + "UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation." + "MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation." + "CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation." + "NumericPasswordValidator", + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = "en-us" + +TIME_ZONE = "UTC" + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ +STATIC_URL = f"/{PATH_PREFIX}/static/" + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +REST_FRAMEWORK = { + "DEFAULT_PERMISSION_CLASSES": [], # TODO: Update once auth is figured + "TEST_REQUEST_DEFAULT_FORMAT": "json", + "EXCEPTION_HANDLER": "middleware.exception.drf_logging_exc_handler", +} + +# These paths will work without authentication +WHITELISTED_PATHS_LIST = [ + "/login", + "/home", + "/callback", + "/favicon.ico", + "/logout", + "/signup", +] +WHITELISTED_PATHS = [f"/{PATH_PREFIX}{PATH}" for PATH in WHITELISTED_PATHS_LIST] +# White lists workflow-api-deployment path +WHITELISTED_PATHS.append(f"/{API_DEPLOYMENT_PATH_PREFIX}") + +# White list paths under tenant paths +TENANT_ACCESSIBLE_PUBLIC_PATHS_LIST = ["/oauth", "/organization", "/doc"] +TENANT_ACCESSIBLE_PUBLIC_PATHS = [ + f"/{PATH_PREFIX}{PATH}" for PATH in TENANT_ACCESSIBLE_PUBLIC_PATHS_LIST +] + +# API Doc Generator Settings +# https://drf-yasg.readthedocs.io/en/stable/settings.html +REDOC_SETTINGS = { + "PATH_IN_MIDDLE": True, + "REQUIRED_PROPS_FIRST": True, +} + +# Social Auth Settings +SOCIAL_AUTH_LOGIN_REDIRECT_URL = ( + f"{WEB_APP_ORIGIN_URL}/oauth-status/?status=success" +) +SOCIAL_AUTH_LOGIN_ERROR_URL = f"{WEB_APP_ORIGIN_URL}/oauth-status/?status=error" +SOCIAL_AUTH_EXTRA_DATA_EXPIRATION_TIME_IN_SECOND = os.environ.get( + "SOCIAL_AUTH_EXTRA_DATA_EXPIRATION_TIME_IN_SECOND", 3600 +) +SOCIAL_AUTH_USER_MODEL = "account.User" +SOCIAL_AUTH_STORAGE = "connector_auth.models.ConnectorDjangoStorage" +SOCIAL_AUTH_JSONFIELD_ENABLED = True +SOCIAL_AUTH_URL_NAMESPACE = "social" +SOCIAL_AUTH_FIELDS_STORED_IN_SESSION = ["oauth-key", "connector-guid"] +SOCIAL_AUTH_TRAILING_SLASH = False + +for key in [ + "GOOGLE_OAUTH2_KEY", + "GOOGLE_OAUTH2_SECRET", +]: + exec("SOCIAL_AUTH_{key} = os.environ.get('{key}')".format(key=key)) + +SOCIAL_AUTH_PIPELINE = ( + # Checks if user is authenticated + "connector_auth.pipeline.common.check_user_exists", + # Gets user details from provider + "social_core.pipeline.social_auth.social_details", + "social_core.pipeline.social_auth.social_uid", + # Cache secrets and fields in redis + "connector_auth.pipeline.common.cache_oauth_creds", +) + +# Social Auth: Google OAuth2 +# Default takes care of sign in flow which we don't need for connectors +SOCIAL_AUTH_GOOGLE_OAUTH2_IGNORE_DEFAULT_SCOPE = True +SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [ + "https://www.googleapis.com/auth/userinfo.profile", + "https://www.googleapis.com/auth/drive", +] +SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = { + "access_type": "offline", + "include_granted_scopes": "true", + "prompt": "consent", +} +SOCIAL_AUTH_GOOGLE_OAUTH2_USE_UNIQUE_USER_ID = True + + +# Always keep this line at the bottom of the file. +if missing_settings: + ERROR_MESSAGE = "Below required settings are missing.\n" + ",\n".join( + missing_settings + ) + raise ValueError(ERROR_MESSAGE) diff --git a/backend/backend/settings/dev.py b/backend/backend/settings/dev.py new file mode 100644 index 000000000..15297777b --- /dev/null +++ b/backend/backend/settings/dev.py @@ -0,0 +1,27 @@ +from backend.settings.base import * # noqa: F401, F403 + +DEBUG = True + +X_FRAME_OPTIONS = "http://localhost:3000" +X_FRAME_OPTIONS = "ALLOW-FROM http://localhost:3000" + +CORS_ALLOWED_ORIGINS = [ + "http://localhost:3000", + "http://127.0.0.1:3000", + "https://dev-3xlzwou1raoituv0.us.auth0.com", + # Other allowed origins if needed +] + +CORS_ORIGIN_WHITELIST = [ + "http://localhost:3000", + "http://127.0.0.1:3000", + "https://dev-3xlzwou1raoituv0.us.auth0.com", + # Other allowed origins if needed +] + +CORS_ALLOW_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"] + +CORS_ALLOW_HEADERS = [ + "authorization", + "content-type", +] diff --git a/backend/backend/settings/test_cases.py b/backend/backend/settings/test_cases.py new file mode 100644 index 000000000..4656e0749 --- /dev/null +++ b/backend/backend/settings/test_cases.py @@ -0,0 +1,3 @@ +from backend.settings.base import * # noqa: F401, F403 + +DEBUG = True diff --git a/backend/backend/urls.py b/backend/backend/urls.py new file mode 100644 index 000000000..505d279c7 --- /dev/null +++ b/backend/backend/urls.py @@ -0,0 +1,53 @@ +"""URL configuration for backend project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/4.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" + +from backend.constants import UrlPathConstants +from django.conf.urls import * # noqa: F401, F403 +from django.urls import include, path + +urlpatterns = [ + path("", include("tenant_account.urls")), + path("", include("prompt.urls")), + path("", include("project.urls")), + path("", include("connector.urls")), + path("", include("connector_processor.urls")), + path("", include("adapter_processor.urls")), + path("", include("file_management.urls")), + path("", include("tool_instance.urls")), + path("", include("cron_expression_generator.urls")), + path("", include("pipeline.urls")), + path("", include("apps.urls")), + path("workflow/", include("workflow_manager.urls")), + path("platform/", include("platform_settings.urls")), + path("api/", include("api.urls")), + path( + UrlPathConstants.PROMPT_STUDIO, + include("prompt_studio.prompt_profile_manager.urls"), + ), + path( + UrlPathConstants.PROMPT_STUDIO, + include("prompt_studio.prompt_studio.urls"), + ), + path("", include("prompt_studio.prompt_studio_core.urls")), + path( + UrlPathConstants.PROMPT_STUDIO, + include("prompt_studio.prompt_studio_registry.urls"), + ), + path( + UrlPathConstants.PROMPT_STUDIO, + include("prompt_studio.prompt_studio_output_manager.urls"), + ), +] diff --git a/backend/backend/wsgi.py b/backend/backend/wsgi.py new file mode 100644 index 000000000..536554420 --- /dev/null +++ b/backend/backend/wsgi.py @@ -0,0 +1,25 @@ +"""WSGI config for backend project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +import socketio +from django.conf import settings +from django.core.wsgi import get_wsgi_application +from dotenv import load_dotenv +from log_events.views import sio + +load_dotenv() +path_prefix = settings.PATH_PREFIX + +os.environ.setdefault( + "DJANGO_SETTINGS_MODULE", + os.environ.get("DJANGO_SETTINGS_MODULE", "backend.settings.dev"), +) +django_app = get_wsgi_application() +application = socketio.WSGIApp(sio, django_app,socketio_path=f"{path_prefix}/socket") diff --git a/backend/connector/__init__.py b/backend/connector/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/connector/admin.py b/backend/connector/admin.py new file mode 100644 index 000000000..3750fb4c5 --- /dev/null +++ b/backend/connector/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import ConnectorInstance + +admin.site.register(ConnectorInstance) diff --git a/backend/connector/apps.py b/backend/connector/apps.py new file mode 100644 index 000000000..b9908c2e6 --- /dev/null +++ b/backend/connector/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ConnectorConfig(AppConfig): + name = "connector" diff --git a/backend/connector/connector_instance_helper.py b/backend/connector/connector_instance_helper.py new file mode 100644 index 000000000..098f5a691 --- /dev/null +++ b/backend/connector/connector_instance_helper.py @@ -0,0 +1,316 @@ +import logging +from typing import Any, Optional + +from account.models import User +from connector.constants import ConnectorInstanceConstant +from connector.models import ConnectorInstance +from connector.unstract_account import UnstractAccount +from django.conf import settings +from django.db import connection +from unstract.connectors.filesystems.ucs import UnstractCloudStorage +from unstract.connectors.filesystems.ucs.constants import UCSKey +from workflow_manager.workflow.models.workflow import Workflow + +logger = logging.getLogger(__name__) + + +class ConnectorInstanceHelper: + @staticmethod + def create_default_gcs_connector(workflow: Workflow, user: User) -> None: + """Method to create default storage connector. + + Args: + org_id (str) + workflow (Workflow) + user (User) + """ + org_schema = connection.tenant.schema_name + if not user.project_storage_created: + logger.info("Creating default storage") + account = UnstractAccount(org_schema, user.email) + account.provision_s3_storage() + account.upload_sample_files() + user.project_storage_created = True + user.save() + logger.info("default storage created successfully.") + + logger.info("Adding connectors to Unstract") + connector_name = ConnectorInstanceConstant.USER_STORAGE + gcs_id = UnstractCloudStorage.get_id() + bucket_name = settings.UNSTRACT_FREE_STORAGE_BUCKET_NAME + base_path = f"{bucket_name}/{org_schema}/{user.email}" + + connector_metadata = { + UCSKey.KEY: settings.GOOGLE_STORAGE_ACCESS_KEY_ID, + UCSKey.SECRET: settings.GOOGLE_STORAGE_SECRET_ACCESS_KEY, + UCSKey.BUCKET: bucket_name, + UCSKey.ENDPOINT_URL: settings.GOOGLE_STORAGE_BASE_URL, + } + connector_metadata__input = { + **connector_metadata, + UCSKey.PATH: base_path + "/input", + } + connector_metadata__output = { + **connector_metadata, + UCSKey.PATH: base_path + "/output", + } + ConnectorInstance.objects.create( + connector_name=connector_name, + workflow=workflow, + created_by=user, + connector_id=gcs_id, + connector_metadata=connector_metadata__input, + connector_type=ConnectorInstance.ConnectorType.INPUT, + connector_mode=ConnectorInstance.ConnectorMode.FILE_SYSTEM, + ) + ConnectorInstance.objects.create( + connector_name=connector_name, + workflow=workflow, + created_by=user, + connector_id=gcs_id, + connector_metadata=connector_metadata__output, + connector_type=ConnectorInstance.ConnectorType.OUTPUT, + connector_mode=ConnectorInstance.ConnectorMode.FILE_SYSTEM, + ) + logger.info("Connectors added successfully.") + + @staticmethod + def get_connector_instances_by_workflow( + workflow_id: str, + connector_type: tuple[str, str], + connector_mode: Optional[tuple[int, str]] = None, + values: Optional[list[str]] = None, + connector_name: Optional[str] = None, + ) -> list[ConnectorInstance]: + """Method to get connector instances by workflow. + + Args: + workflow_id (str) + connector_type (tuple[str, str]): Specifies input/output + connector_mode (Optional[tuple[int, str]], optional): + Specifies database/file + values (Optional[list[str]], optional): Defaults to None. + connector_name (Optional[str], optional): Defaults to None. + + Returns: + list[ConnectorInstance] + """ + logger.info(f"Setting connector mode to {connector_mode}") + filter_params: dict[str, Any] = { + "workflow": workflow_id, + "connector_type": connector_type, + } + if connector_mode is not None: + filter_params["connector_mode"] = connector_mode + if connector_name is not None: + filter_params["connector_name"] = connector_name + + connector_instances = ConnectorInstance.objects.filter( + **filter_params + ).all() + logger.info(f"Retrived connector instance values {connector_instances}") + if values is not None: + filtered_connector_instances = connector_instances.values(*values) + logger.info( + f"Returning filtered \ + connector instance value {filtered_connector_instances}" + ) + return list(filtered_connector_instances) + logger.info(f"Returning connector instances {connector_instances}") + return list(connector_instances) + + @staticmethod + def get_connector_instance_by_workflow( + workflow_id: str, + connector_type: tuple[str, str], + connector_mode: Optional[tuple[int, str]] = None, + connector_name: Optional[str] = None, + ) -> Optional[ConnectorInstance]: + """Get one connector instance. + + Use this method if the connector instance is unique for \ + filter_params + Args: + workflow_id (str): _description_ + connector_type (tuple[str, str]): Specifies input/output + connector_mode (Optional[tuple[int, str]], optional). + Specifies database/filesystem + values (Optional[list[str]], optional). + connector_name (Optional[str], optional). + + Returns: + list[ConnectorInstance]: _description_ + """ + logger.info("Fetching connector instance by workflow") + filter_params: dict[str, Any] = { + "workflow": workflow_id, + "connector_type": connector_type, + } + if connector_mode is not None: + filter_params["connector_mode"] = connector_mode + if connector_name is not None: + filter_params["connector_name"] = connector_name + + try: + connector_instance: ConnectorInstance = ( + ConnectorInstance.objects.filter(**filter_params).first() + ) + except Exception as exc: + logger.error( + f"Error occured while fetching connector instances {exc}" + ) + raise exc + + return connector_instance + + @staticmethod + def get_input_connector_instance_by_name_for_workflow( + workflow_id: str, + connector_name: str, + ) -> Optional[ConnectorInstance]: + """Method to get Input connector instance name from the workflow. + + Args: + workflow_id (str) + connector_name (str) + + Returns: + Optional[ConnectorInstance] + """ + return ConnectorInstanceHelper.get_connector_instance_by_workflow( + workflow_id=workflow_id, + connector_type=ConnectorInstance.ConnectorType.INPUT, + connector_name=connector_name, + ) + + @staticmethod + def get_output_connector_instance_by_name_for_workflow( + workflow_id: str, + connector_name: str, + ) -> Optional[ConnectorInstance]: + """Method to get output connector name by Workflow. + + Args: + workflow_id (str) + connector_name (str) + + Returns: + Optional[ConnectorInstance] + """ + return ConnectorInstanceHelper.get_connector_instance_by_workflow( + workflow_id=workflow_id, + connector_type=ConnectorInstance.ConnectorType.OUTPUT, + connector_name=connector_name, + ) + + @staticmethod + def get_input_connector_instances_by_workflow( + workflow_id: str, + ) -> list[ConnectorInstance]: + """Method to get connector instances by workflow. + + Args: + workflow_id (str) + + Returns: + list[ConnectorInstance] + """ + return ConnectorInstanceHelper.get_connector_instances_by_workflow( + workflow_id, ConnectorInstance.ConnectorType.INPUT + ) + + @staticmethod + def get_output_connector_instances_by_workflow( + workflow_id: str, + ) -> list[ConnectorInstance]: + """Method to get output connector instances by workflow. + + Args: + workflow_id (str): _description_ + + Returns: + list[ConnectorInstance]: _description_ + """ + return ConnectorInstanceHelper.get_connector_instances_by_workflow( + workflow_id, ConnectorInstance.ConnectorType.OUTPUT + ) + + @staticmethod + def get_file_system_input_connector_instances_by_workflow( + workflow_id: str, values: Optional[list[str]] = None + ) -> list[ConnectorInstance]: + """Method to fetch file system connector by workflow. + + Args: + workflow_id (str): + values (Optional[list[str]], optional) + + Returns: + list[ConnectorInstance] + """ + return ConnectorInstanceHelper.get_connector_instances_by_workflow( + workflow_id, + ConnectorInstance.ConnectorType.INPUT, + ConnectorInstance.ConnectorMode.FILE_SYSTEM, + values, + ) + + @staticmethod + def get_file_system_output_connector_instances_by_workflow( + workflow_id: str, values: Optional[list[str]] = None + ) -> list[ConnectorInstance]: + """Method to get file system output connector by workflow. + + Args: + workflow_id (str) + values (Optional[list[str]], optional) + + Returns: + list[ConnectorInstance] + """ + return ConnectorInstanceHelper.get_connector_instances_by_workflow( + workflow_id, + ConnectorInstance.ConnectorType.OUTPUT, + ConnectorInstance.ConnectorMode.FILE_SYSTEM, + values, + ) + + @staticmethod + def get_database_input_connector_instances_by_workflow( + workflow_id: str, values: Optional[list[str]] = None + ) -> list[ConnectorInstance]: + """Method to fetch input database connectors by workflow. + + Args: + workflow_id (str) + values (Optional[list[str]], optional) + + Returns: + list[ConnectorInstance] + """ + return ConnectorInstanceHelper.get_connector_instances_by_workflow( + workflow_id, + ConnectorInstance.ConnectorType.INPUT, + ConnectorInstance.ConnectorMode.DATABASE, + values, + ) + + @staticmethod + def get_database_output_connector_instances_by_workflow( + workflow_id: str, values: Optional[list[str]] = None + ) -> list[ConnectorInstance]: + """Method to fetch output database connectors by workflow. + + Args: + workflow_id (str) + values (Optional[list[str]], optional) + + Returns: + list[ConnectorInstance] + """ + return ConnectorInstanceHelper.get_connector_instances_by_workflow( + workflow_id, + ConnectorInstance.ConnectorType.OUTPUT, + ConnectorInstance.ConnectorMode.DATABASE, + values, + ) diff --git a/backend/connector/constants.py b/backend/connector/constants.py new file mode 100644 index 000000000..5b9234e6e --- /dev/null +++ b/backend/connector/constants.py @@ -0,0 +1,17 @@ +class ConnectorInstanceKey: + CONNECTOR_ID = "connector_id" + CONNECTOR_NAME = "connector_name" + CONNECTOR_TYPE = "connector_type" + CONNECTOR_MODE = "connector_mode" + CONNECTOR_VERSION = "connector_version" + CONNECTOR_AUTH = "connector_auth" + CONNECTOR_METADATA = "connector_metadata" + CONNECTOR_METADATA_B = "connector_metadata_b" + CONNECTOR_EXISTS = ( + "Connector with this configuration already exists in this project." + ) + DUPLICATE_API = "It appears that a duplicate call may have been made." + + +class ConnectorInstanceConstant: + USER_STORAGE = "User Storage" diff --git a/backend/connector/fields.py b/backend/connector/fields.py new file mode 100644 index 000000000..2ade7a897 --- /dev/null +++ b/backend/connector/fields.py @@ -0,0 +1,38 @@ +from datetime import datetime + +from connector_auth.constants import SocialAuthConstants +from connector_auth.models import ConnectorAuth +from django.db import models +import logging + +logger = logging.getLogger(__name__) + + +class ConnectorAuthJSONField(models.JSONField): + def from_db_value(self, value, expression, connection): # type: ignore + """ Overrding default function. """ + metadata = super().from_db_value(value, expression, connection) + provider = metadata.get(SocialAuthConstants.PROVIDER) + uid = metadata.get(SocialAuthConstants.UID) + if provider and uid: + refresh_after_str = metadata.get(SocialAuthConstants.REFRESH_AFTER) + if refresh_after_str: + refresh_after = datetime.strptime( + refresh_after_str, SocialAuthConstants.REFRESH_AFTER_FORMAT + ) + if datetime.now() > refresh_after: + metadata = self._refresh_tokens(provider, uid) + return metadata + + def _refresh_tokens(self, provider: str, uid: str) -> dict[str, str]: + """Retrieves PSA object and refreshes the token if necessary.""" + connector_auth: ConnectorAuth = ConnectorAuth.get_social_auth( + provider=provider, uid=uid + ) + tokens_refreshed = False + if connector_auth: + ( + connector_metadata, + tokens_refreshed, + ) = connector_auth.get_and_refresh_tokens() + return connector_metadata # type: ignore diff --git a/backend/connector/migrations/0001_initial.py b/backend/connector/migrations/0001_initial.py new file mode 100644 index 000000000..08d18dce2 --- /dev/null +++ b/backend/connector/migrations/0001_initial.py @@ -0,0 +1,122 @@ +# Generated by Django 4.2.1 on 2024-01-23 11:18 + +import uuid + +import connector.fields +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + ("project", "0001_initial"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("workflow", "0001_initial"), + ("connector_auth", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="ConnectorInstance", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ("connector_name", models.TextField(max_length=128)), + ("connector_id", models.CharField(default="", max_length=128)), + ( + "connector_metadata", + connector.fields.ConnectorAuthJSONField( + db_column="connector_metadata", default=dict + ), + ), + ( + "connector_version", + models.CharField(default="", max_length=64), + ), + ( + "connector_type", + models.CharField( + choices=[("INPUT", "Input"), ("OUTPUT", "Output")] + ), + ), + ( + "connector_mode", + models.CharField( + choices=[ + (0, "UNKNOWN"), + (1, "FILE_SYSTEM"), + (2, "DATABASE"), + ], + db_comment="0: UNKNOWN, 1: FILE_SYSTEM, 2: DATABASE", + default=0, + ), + ), + ( + "connector_auth", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="connector_auth.connectorauth", + ), + ), + ( + "created_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="created_connectors", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="modified_connectors", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "project", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="project_connectors", + to="project.project", + ), + ), + ( + "workflow", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="workflow_connectors", + to="workflow.workflow", + ), + ), + ], + ), + migrations.AddConstraint( + model_name="connectorinstance", + constraint=models.UniqueConstraint( + fields=("connector_name", "workflow", "connector_type"), + name="unique_connector", + ), + ), + ] diff --git a/backend/connector/migrations/0002_connectorinstance_connector_metadata_b.py b/backend/connector/migrations/0002_connectorinstance_connector_metadata_b.py new file mode 100644 index 000000000..7f9090a2e --- /dev/null +++ b/backend/connector/migrations/0002_connectorinstance_connector_metadata_b.py @@ -0,0 +1,42 @@ +# Generated by Django 4.2.1 on 2024-02-16 06:50 + +import json +from typing import Any + +from account.models import EncryptionSecret +from connector.models import ConnectorInstance +from cryptography.fernet import Fernet +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("connector", "0001_initial"), + ("account", "0005_encryptionsecret"), + ] + + def EncryptCredentials(apps: Any, schema_editor: Any) -> None: + encryption_secret: EncryptionSecret = EncryptionSecret.objects.get() + f: Fernet = Fernet(encryption_secret.key.encode("utf-8")) + queryset = ConnectorInstance.objects.all() + + for obj in queryset: # type: ignore + # Access attributes of the object + + if hasattr(obj, "connector_metadata"): + json_string: str = json.dumps(obj.connector_metadata) + obj.connector_metadata_b = f.encrypt( + json_string.encode("utf-8") + ) + obj.save() + + operations = [ + migrations.AddField( + model_name="connectorinstance", + name="connector_metadata_b", + field=models.BinaryField(null=True), + ), + migrations.RunPython( + EncryptCredentials, reverse_code=migrations.RunPython.noop + ), + ] diff --git a/backend/connector/migrations/__init__.py b/backend/connector/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/connector/models.py b/backend/connector/models.py new file mode 100644 index 000000000..cc58ee5be --- /dev/null +++ b/backend/connector/models.py @@ -0,0 +1,116 @@ +import uuid + +from account.models import User +from connector.fields import ConnectorAuthJSONField +from connector_auth.models import ConnectorAuth +from connector_processor.connector_processor import ConnectorProcessor +from connector_processor.constants import ConnectorKeys +from django.db import models +from project.models import Project +from utils.models.base_model import BaseModel +from workflow_manager.workflow.models import Workflow + +from backend.constants import FieldLengthConstants as FLC + +CONNECTOR_NAME_SIZE = 128 +VERSION_NAME_SIZE = 64 + + +class ConnectorInstance(BaseModel): + class ConnectorType(models.TextChoices): + INPUT = "INPUT", "Input" + OUTPUT = "OUTPUT", "Output" + + class ConnectorMode(models.IntegerChoices): + UNKNOWN = 0, "UNKNOWN" + FILE_SYSTEM = 1, "FILE_SYSTEM" + DATABASE = 2, "DATABASE" + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + connector_name = models.TextField( + max_length=CONNECTOR_NAME_SIZE, null=False, blank=False + ) + project = models.ForeignKey( + Project, + on_delete=models.CASCADE, + related_name="project_connectors", + null=True, + blank=True, + ) + workflow = models.ForeignKey( + Workflow, + on_delete=models.CASCADE, + related_name="workflow_connectors", + null=False, + blank=False, + ) + connector_id = models.CharField( + max_length=FLC.CONNECTOR_ID_LENGTH, default="" + ) + # TODO Required to be removed + connector_metadata = ConnectorAuthJSONField( + db_column="connector_metadata", null=False, blank=False, default=dict + ) + connector_metadata_b = models.BinaryField(null=True) + connector_version = models.CharField( + max_length=VERSION_NAME_SIZE, default="" + ) + connector_type = models.CharField(choices=ConnectorType.choices) + connector_auth = models.ForeignKey( + ConnectorAuth, on_delete=models.SET_NULL, null=True, blank=True + ) + connector_mode = models.CharField( + choices=ConnectorMode.choices, + default=ConnectorMode.UNKNOWN, + db_comment="0: UNKNOWN, 1: FILE_SYSTEM, 2: DATABASE", + ) + + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="created_connectors", + null=True, + blank=True, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="modified_connectors", + null=True, + blank=True, + ) + + def get_connector_metadata(self) -> dict[str, str]: + """Gets connector metadata and refreshes the tokens if needed in case + of OAuth.""" + tokens_refreshed = False + if self.connector_auth: + ( + self.connector_metadata, + tokens_refreshed, + ) = self.connector_auth.get_and_refresh_tokens() + if tokens_refreshed: + self.save() + return self.connector_metadata + + @staticmethod + def supportsOAuth(connector_id: str) -> bool: + return bool( + ConnectorProcessor.get_connector_data_with_key( + connector_id, ConnectorKeys.OAUTH + ) + ) + + def __str__(self) -> str: + return ( + f"Connector({self.id}, type{self.connector_type}," + f" workflow: {self.workflow})" + ) + + class Meta: + constraints = [ + models.UniqueConstraint( + fields=["connector_name", "workflow", "connector_type"], + name="unique_connector", + ), + ] diff --git a/backend/connector/serializers.py b/backend/connector/serializers.py new file mode 100644 index 000000000..4b664cb67 --- /dev/null +++ b/backend/connector/serializers.py @@ -0,0 +1,93 @@ +import json +import logging +from collections import OrderedDict +from typing import Any, Optional + +from account.models import EncryptionSecret +from connector.constants import ConnectorInstanceKey as CIKey +from connector_auth.models import ConnectorAuth +from connector_auth.pipeline.common import ConnectorAuthHelper +from connector_processor.connector_processor import ConnectorProcessor +from connector_processor.constants import ConnectorKeys +from connector_processor.exceptions import OAuthTimeOut +from cryptography.fernet import Fernet +from utils.serializer_utils import SerializerUtils + +from backend.serializers import AuditSerializer +from unstract.connectors.filesystems.ucs import UnstractCloudStorage + +from .models import ConnectorInstance + +logger = logging.getLogger(__name__) + + +class ConnectorInstanceSerializer(AuditSerializer): + class Meta: + model = ConnectorInstance + fields = "__all__" + + def save(self, **kwargs): # type: ignore + user = self.context.get("request").user or None + connector_id: str = kwargs[CIKey.CONNECTOR_ID] + connector_oauth: Optional[ConnectorAuth] = None + if ( + ConnectorInstance.supportsOAuth(connector_id=connector_id) + and CIKey.CONNECTOR_METADATA in kwargs + ): + try: + connector_oauth = ( + ConnectorAuthHelper.get_or_create_connector_auth( + user=user, # type: ignore + oauth_credentials=kwargs[CIKey.CONNECTOR_METADATA], + ) + ) + kwargs[CIKey.CONNECTOR_AUTH] = connector_oauth + ( + kwargs[CIKey.CONNECTOR_METADATA], + refresh_status, + ) = connector_oauth.get_and_refresh_tokens() + except Exception as exc: + logger.error(f"Error while obtaining ConnectorAuth: {exc}") + raise OAuthTimeOut + + connector_mode = ConnectorProcessor.get_connector_data_with_key( + connector_id, CIKey.CONNECTOR_MODE + ) + kwargs[CIKey.CONNECTOR_MODE] = connector_mode.value + + encryption_secret: EncryptionSecret = EncryptionSecret.objects.get() + f: Fernet = Fernet(encryption_secret.key.encode("utf-8")) + json_string: str = json.dumps(kwargs.pop(CIKey.CONNECTOR_METADATA)) + if self.validated_data: + self.validated_data.pop(CIKey.CONNECTOR_METADATA) + + kwargs[CIKey.CONNECTOR_METADATA_B] = f.encrypt( + json_string.encode("utf-8") + ) + + instance = super().save(**kwargs) + return instance + + def to_representation(self, instance: ConnectorInstance) -> dict[str, str]: + # to remove the sensitive fields being returned + rep: OrderedDict[str, Any] = super().to_representation(instance) + if instance.connector_id == UnstractCloudStorage.get_id(): + rep[CIKey.CONNECTOR_METADATA] = {} + if SerializerUtils.check_context_for_GET_or_POST(context=self.context): + rep.pop(CIKey.CONNECTOR_AUTH) + # set icon fields for UI + rep[ + ConnectorKeys.ICON + ] = ConnectorProcessor.get_connector_data_with_key( + instance.connector_id, ConnectorKeys.ICON + ) + encryption_secret: EncryptionSecret = EncryptionSecret.objects.get() + f: Fernet = Fernet(encryption_secret.key.encode("utf-8")) + + rep.pop(CIKey.CONNECTOR_METADATA_B) + if instance.connector_metadata_b: + adapter_metadata = json.loads( + f.decrypt(bytes(instance.connector_metadata_b).decode("utf-8")) + ) + rep[CIKey.CONNECTOR_METADATA] = adapter_metadata + return rep diff --git a/backend/connector/tests/conftest.py b/backend/connector/tests/conftest.py new file mode 100644 index 000000000..89f1715a1 --- /dev/null +++ b/backend/connector/tests/conftest.py @@ -0,0 +1,9 @@ +import pytest +from django.core.management import call_command + + +@pytest.fixture(scope="session") +def django_db_setup(django_db_blocker): # type: ignore + fixtures = ["./connector/tests/fixtures/fixtures_0001.json"] + with django_db_blocker.unblock(): + call_command("loaddata", *fixtures) diff --git a/backend/connector/tests/connector_tests.py b/backend/connector/tests/connector_tests.py new file mode 100644 index 000000000..f967a7a4e --- /dev/null +++ b/backend/connector/tests/connector_tests.py @@ -0,0 +1,326 @@ +# mypy: ignore-errors +import pytest +from connector.models import ConnectorInstance +from django.urls import reverse +from rest_framework import status +from rest_framework.test import APITestCase + +pytestmark = pytest.mark.django_db + + +@pytest.mark.connector +class TestConnector(APITestCase): + def test_connector_list(self) -> None: + """Tests to List the connectors.""" + + url = reverse("connectors_v1-list") + response = self.client.get(url) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_connectors_detail(self) -> None: + """Tests to fetch a connector with given pk.""" + + url = reverse("connectors_v1-detail", kwargs={"pk": 1}) + response = self.client.get(url) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_connectors_detail_not_found(self) -> None: + """Tests for negative case to fetch non exiting key.""" + + url = reverse("connectors_v1-detail", kwargs={"pk": 768}) + response = self.client.get(url) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_connectors_create(self) -> None: + """Tests to create a new ConnectorInstance.""" + + url = reverse("connectors_v1-list") + data = { + "org": 1, + "project": 1, + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + "connector_id": "e3a4512m-efgb-48d5-98a9-3983nd77f", + "connector_metadata": {"drive_link": "sample_url", "sharable_link": True}, + } + response = self.client.post(url, data, format="json") + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(ConnectorInstance.objects.count(), 2) + + def test_connectors_create_with_json_list(self) -> None: + """Tests to create a new connector with list included in the json + field.""" + + url = reverse("connectors_v1-list") + data = { + "org": 1, + "project": 1, + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + "connector_id": "e3a4512m-efgb-48d5-98a9-3983nd77f", + "connector_metadata": { + "drive_link": "sample_url", + "sharable_link": True, + "file_name_list": ["a1", "a2"], + }, + } + response = self.client.post(url, data, format="json") + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(ConnectorInstance.objects.count(), 2) + + def test_connectors_create_with_nested_json(self) -> None: + """Tests to create a new connector with json field as nested json.""" + + url = reverse("connectors_v1-list") + data = { + "org": 1, + "project": 1, + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + "connector_id": "e3a4512m-efgb-48d5-98a9-3983nd77f", + "connector_metadata": { + "drive_link": "sample_url", + "sharable_link": True, + "sample_metadata_json": {"key1": "value1", "key2": "value2"}, + }, + } + response = self.client.post(url, data, format="json") + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(ConnectorInstance.objects.count(), 2) + + def test_connectors_create_bad_request(self) -> None: + """Tests for negative case to throw error on a wrong access.""" + + url = reverse("connectors_v1-list") + data = { + "org": 5, + "project": 1, + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + "connector_id": "e3a4512m-efgb-48d5-98a9-3983nd77f", + "connector_metadata": { + "drive_link": "sample_url", + "sharable_link": True, + "sample_metadata_json": {"key1": "value1", "key2": "value2"}, + }, + } + response = self.client.post(url, data, format="json") + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_connectors_update_json_field(self) -> None: + """Tests to update connector with json field update.""" + + url = reverse("connectors_v1-detail", kwargs={"pk": 1}) + data = { + "org": 1, + "project": 1, + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + "connector_id": "e3a4512m-efgb-48d5-98a9-3983nd77f", + "connector_metadata": { + "drive_link": "new_sample_url", + "sharable_link": True, + "sample_metadata_json": {"key1": "value1", "key2": "value2"}, + }, + } + response = self.client.put(url, data, format="json") + drive_link = response.data["connector_metadata"]["drive_link"] + self.assertEqual(drive_link, "new_sample_url") + + def test_connectors_update(self) -> None: + """Tests to update connector update single field.""" + + url = reverse("connectors_v1-detail", kwargs={"pk": 1}) + data = { + "org": 1, + "project": 1, + "created_by": 1, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + "connector_id": "e3a4512m-efgb-48d5-98a9-3983nd77f", + "connector_metadata": { + "drive_link": "new_sample_url", + "sharable_link": True, + "sample_metadata_json": {"key1": "value1", "key2": "value2"}, + }, + } + response = self.client.put(url, data, format="json") + modified_by = response.data["modified_by"] + self.assertEqual(modified_by, 2) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_connectors_update_pk(self) -> None: + """Tests the PUT method for 400 error.""" + + url = reverse("connectors_v1-detail", kwargs={"pk": 1}) + data = { + "org": 2, + "project": 1, + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + "connector_id": "e3a4512m-efgb-48d5-98a9-3983nd77f", + "connector_metadata": { + "drive_link": "new_sample_url", + "sharable_link": True, + "sample_metadata_json": {"key1": "value1", "key2": "value2"}, + }, + } + response = self.client.put(url, data, format="json") + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_connectors_update_json_fields(self) -> None: + """Tests to update ConnectorInstance.""" + + url = reverse("connectors_v1-detail", kwargs={"pk": 1}) + data = { + "org": 1, + "project": 1, + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + "connector_id": "e3a4512m-efgb-48d5-98a9-3983nd77f", + "connector_metadata": { + "drive_link": "new_sample_url", + "sharable_link": True, + "sample_metadata_json": {"key1": "value1", "key2": "value2"}, + }, + } + response = self.client.put(url, data, format="json") + nested_value = response.data["connector_metadata"]["sample_metadata_json"][ + "key1" + ] + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(nested_value, "value1") + + def test_connectors_update_json_list_fields(self) -> None: + """Tests to update connector to the third second level of json.""" + + url = reverse("connectors_v1-detail", kwargs={"pk": 1}) + data = { + "org": 1, + "project": 1, + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + "connector_id": "e3a4512m-efgb-48d5-98a9-3983nd77f", + "connector_metadata": { + "drive_link": "new_sample_url", + "sharable_link": True, + "sample_metadata_json": {"key1": "value1", "key2": "value2"}, + "file_list": ["a1", "a2", "a3"], + }, + } + response = self.client.put(url, data, format="json") + nested_value = response.data["connector_metadata"]["sample_metadata_json"][ + "key1" + ] + nested_list = response.data["connector_metadata"]["file_list"] + last_val = nested_list.pop() + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(nested_value, "value1") + self.assertEqual(last_val, "a3") + + # @pytest.mark.xfail(raises=KeyError) + # def test_connectors_update_json_fields_failed(self) -> None: + # """Tests to update connector to the second level of JSON with a wrong + # key.""" + + # url = reverse("connectors_v1-detail", kwargs={"pk": 1}) + # data = { + # "org": 1, + # "project": 1, + # "created_by": 2, + # "modified_by": 2, + # "modified_at": "2023-06-14T05:28:47.759Z", + # "connector_id": "e3a4512m-efgb-48d5-98a9-3983nd77f", + # "connector_metadata": { + # "drive_link": "new_sample_url", + # "sharable_link": True, + # "sample_metadata_json": {"key1": "value1", "key2": "value2"}, + # }, + # } + # response = self.client.put(url, data, format="json") + # nested_value = response.data["connector_metadata"]["sample_metadata_json"][ + # "key00" + # ] + + # @pytest.mark.xfail(raises=KeyError) + # def test_connectors_update_json_nested_failed(self) -> None: + # """Tests to update connector to test a first level of json with a wrong + # key.""" + + # url = reverse("connectors_v1-detail", kwargs={"pk": 1}) + # data = { + # "org": 1, + # "project": 1, + # "created_by": 2, + # "modified_by": 2, + # "modified_at": "2023-06-14T05:28:47.759Z", + # "connector_id": "e3a4512m-efgb-48d5-98a9-3983nd77f", + # "connector_metadata": { + # "drive_link": "new_sample_url", + # "sharable_link": True, + # "sample_metadata_json": {"key1": "value1", "key2": "value2"}, + # }, + # } + # response = self.client.put(url, data, format="json") + # nested_value = response.data["connector_metadata"]["sample_metadata_jsonNew"] + + def test_connectors_update_field(self) -> None: + """Tests the PATCH method.""" + + url = reverse("connectors_v1-detail", kwargs={"pk": 1}) + data = {"connector_id": "e3a4512m-efgb-48d5-98a9-3983ntest"} + response = self.client.patch(url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_200_OK) + connector_id = response.data["connector_id"] + + self.assertEqual( + connector_id, + ConnectorInstance.objects.get(connector_id=connector_id).connector_id, + ) + + def test_connectors_update_json_field_patch(self) -> None: + """Tests the PATCH method.""" + + url = reverse("connectors_v1-detail", kwargs={"pk": 1}) + data = { + "connector_metadata": { + "drive_link": "patch_update_url", + "sharable_link": True, + "sample_metadata_json": {"key1": "patch_update1", "key2": "value2"}, + } + } + + response = self.client.patch(url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_200_OK) + drive_link = response.data["connector_metadata"]["drive_link"] + + self.assertEqual(drive_link, "patch_update_url") + + def test_connectors_delete(self) -> None: + """Tests the DELETE method.""" + + url = reverse("connectors_v1-detail", kwargs={"pk": 1}) + response = self.client.delete(url, format="json") + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + + url = reverse("connectors_v1-detail", kwargs={"pk": 1}) + response = self.client.get(url) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) diff --git a/backend/connector/tests/fixtures/fixtures_0001.json b/backend/connector/tests/fixtures/fixtures_0001.json new file mode 100644 index 000000000..55b39e6d8 --- /dev/null +++ b/backend/connector/tests/fixtures/fixtures_0001.json @@ -0,0 +1,67 @@ +[ + { + "model": "account.org", + "pk": 1, + "fields": { + "org_name": "Zipstack", + "created_by": 1, + "modified_by": 1, + "modified_at": "2023-06-14T05:28:47.739Z" + } + }, + { + "model": "account.user", + "pk": 1, + "fields": { + "org": 1, + "email": "johndoe@gmail.com", + "first_name": "John", + "last_name": "Doe", + "is_admin": true, + "created_by": null, + "modified_by": null, + "modified_at": "2023-06-14T05:28:47.744Z" + } + }, + { + "model": "account.user", + "pk": 2, + "fields": { + "org": 1, + "email": "user1@gmail.com", + "first_name": "Ron", + "last_name": "Stone", + "is_admin": false, + "created_by": 1, + "modified_by": 1, + "modified_at": "2023-06-14T05:28:47.750Z" + } + }, + { + "model": "project.project", + "pk": 1, + "fields": { + "org": 1, + "project_name": "Unstract Test", + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z" + } + }, + { + "model": "connector.connector", + "pk": 1, + "fields": { + "org": 1, + "project": 1, + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + "connector_id": "e38a59b7-efbb-48d5-9da6-3a0cf2d882a0", + "connector_metadata": { + "connector_type": "gdrive", + "auth_type": "oauth" + } + } + } +] diff --git a/backend/connector/unstract_account.py b/backend/connector/unstract_account.py new file mode 100644 index 000000000..96d998a22 --- /dev/null +++ b/backend/connector/unstract_account.py @@ -0,0 +1,78 @@ +import logging +import os + +import boto3 +from botocore.exceptions import ClientError +from django.conf import settings + +logger = logging.getLogger(__name__) + + +# TODO: UnstractAccount need to be pluggable +class UnstractAccount: + def __init__(self, tenant: str, username: str) -> None: + self.tenant = tenant + self.username = username + + def provision_s3_storage(self) -> None: + access_key = settings.GOOGLE_STORAGE_ACCESS_KEY_ID + secret_key = settings.GOOGLE_STORAGE_SECRET_ACCESS_KEY + bucket_name: str = settings.UNSTRACT_FREE_STORAGE_BUCKET_NAME + + s3 = boto3.client( + "s3", + aws_access_key_id=access_key, + aws_secret_access_key=secret_key, + endpoint_url="https://storage.googleapis.com", + ) + + # Check if folder exists and create if it is not available + account_folder = f"{self.tenant}/{self.username}/input/examples/" + try: + logger.info(f"Checking if folder {account_folder} exists...") + s3.head_object(Bucket=bucket_name, Key=account_folder) + logger.info(f"Folder {account_folder} already exists") + except ClientError as e: + logger.info(f"{bucket_name} Folder {account_folder} does not exist") + if e.response["Error"]["Code"] == "404": + logger.info( + f"Folder {account_folder} does not exist. Creating it..." + ) + s3.put_object(Bucket=bucket_name, Key=account_folder) + account_folder_output = f"{self.tenant}/{self.username}/output/" + s3.put_object(Bucket=bucket_name, Key=account_folder_output) + else: + logger.error(f"Error checking folder {account_folder}: {e}") + raise e + + def upload_sample_files(self) -> None: + access_key = settings.GOOGLE_STORAGE_ACCESS_KEY_ID + secret_key = settings.GOOGLE_STORAGE_SECRET_ACCESS_KEY + bucket_name: str = settings.UNSTRACT_FREE_STORAGE_BUCKET_NAME + + s3 = boto3.client( + "s3", + aws_access_key_id=access_key, + aws_secret_access_key=secret_key, + endpoint_url="https://storage.googleapis.com", + ) + + folder = f"{self.tenant}/{self.username}/input/examples/" + + local_path = f"{os.path.dirname(__file__)}/static" + for root, dirs, files in os.walk(local_path): + for file in files: + local_file_path = os.path.join(root, file) + s3_key = os.path.join( + folder, os.path.relpath(local_file_path, local_path) + ) + logger.info( + f"Uploading: {local_file_path} => " + f"s3://{bucket_name}/{s3_key}" + ) + try: + s3.upload_file(local_file_path, bucket_name, s3_key) + except ClientError as e: + logger.error(e) + raise e + logger.info(f"Uploaded: {local_file_path}") diff --git a/backend/connector/urls.py b/backend/connector/urls.py new file mode 100644 index 000000000..84afb940b --- /dev/null +++ b/backend/connector/urls.py @@ -0,0 +1,16 @@ +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns + +from .views import ConnectorInstanceViewSet as CIViewSet + +connector_list = CIViewSet.as_view({"get": "list", "post": "create"}) +connector_detail = CIViewSet.as_view( + {"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"} +) + +urlpatterns = format_suffix_patterns( + [ + path("connector/", connector_list, name="connector-list"), + path("connector//", connector_detail, name="connector-detail"), + ] +) diff --git a/backend/connector/views.py b/backend/connector/views.py new file mode 100644 index 000000000..ef5244935 --- /dev/null +++ b/backend/connector/views.py @@ -0,0 +1,128 @@ +import logging +from typing import Any, Optional + +from account.custom_exceptions import DuplicateData +from backend.constants import RequestKey +from connector.constants import ConnectorInstanceKey as CIKey +from connector_auth.constants import ConnectorAuthKey +from connector_auth.exceptions import CacheMissException, MissingParamException +from connector_auth.pipeline.common import ConnectorAuthHelper +from connector_processor.exceptions import OAuthTimeOut +from django.db import IntegrityError +from django.db.models import QuerySet +from rest_framework import status, viewsets +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning +from utils.filtering import FilterHelper + +from .models import ConnectorInstance +from .serializers import ConnectorInstanceSerializer + +logger = logging.getLogger(__name__) + + +class ConnectorInstanceViewSet(viewsets.ModelViewSet): + versioning_class = URLPathVersioning + queryset = ConnectorInstance.objects.all() + serializer_class = ConnectorInstanceSerializer + + def get_queryset(self) -> Optional[QuerySet]: + filter_args = FilterHelper.build_filter_args( + self.request, + RequestKey.WORKFLOW, + RequestKey.CREATED_BY, + CIKey.CONNECTOR_TYPE, + CIKey.CONNECTOR_MODE, + ) + if filter_args: + queryset = ConnectorInstance.objects.filter(**filter_args) + else: + queryset = ConnectorInstance.objects.all() + return queryset + + def _get_connector_metadata( + self, connector_id: str + ) -> Optional[dict[str, str]]: + """Gets connector metadata for the ConnectorInstance. + + For non oauth based - obtains from request + For oauth based - obtains from cache + + Raises: + e: MissingParamException, CacheMissException + + Returns: + dict[str, str]: Connector creds dict to connect with + """ + connector_metadata = None + if ConnectorInstance.supportsOAuth(connector_id=connector_id): + logger.info(f"Fetching oauth data for {connector_id}") + oauth_key = self.request.query_params.get( + ConnectorAuthKey.OAUTH_KEY + ) + if oauth_key is None: + logger.error("OAuth key missing") + raise MissingParamException(param=ConnectorAuthKey.OAUTH_KEY) + connector_metadata = ConnectorAuthHelper.get_oauth_creds_from_cache( + cache_key=oauth_key, delete_key=True + ) + if connector_metadata is None: + raise CacheMissException( + f"Couldn't find credentials for {oauth_key} from cache" + ) + else: + connector_metadata = self.request.data.get(CIKey.CONNECTOR_METADATA) + return connector_metadata + + def perform_update(self, serializer: ConnectorInstanceSerializer) -> None: + connector_metadata = None + connector_id = self.request.data.get( + CIKey.CONNECTOR_ID, serializer.instance.connector_id + ) + try: + connector_metadata = self._get_connector_metadata(connector_id) + except Exception: + # Suppress here to not shout during partial updates + pass + # Take metadata from instance itself since update + # is performed on other fields of ConnectorInstance + if connector_metadata is None: + connector_metadata = serializer.instance.connector_metadata + serializer.save( + connector_id=connector_id, + connector_metadata=connector_metadata, + modified_by=self.request.user, + ) # type: ignore + + def perform_create(self, serializer: ConnectorInstanceSerializer) -> None: + connector_metadata = None + connector_id = self.request.data.get(CIKey.CONNECTOR_ID) + try: + connector_metadata = self._get_connector_metadata( + connector_id=connector_id + ) + except Exception as exc: + logger.error(f"Error while obtaining ConnectorAuth: {exc}") + raise OAuthTimeOut + serializer.save( + connector_id=connector_id, + connector_metadata=connector_metadata, + created_by=self.request.user, + modified_by=self.request.user, + ) # type: ignore + + def create(self, request: Any) -> Response: + # Overriding default exception behavior + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + try: + self.perform_create(serializer) + except IntegrityError: + raise DuplicateData( + f"{CIKey.CONNECTOR_EXISTS}, \ + {CIKey.DUPLICATE_API}" + ) + headers = self.get_success_headers(serializer.data) + return Response( + serializer.data, status=status.HTTP_201_CREATED, headers=headers + ) diff --git a/backend/connector_auth/__init__.py b/backend/connector_auth/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/connector_auth/admin.py b/backend/connector_auth/admin.py new file mode 100644 index 000000000..014dfec3e --- /dev/null +++ b/backend/connector_auth/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import ConnectorAuth + +admin.site.register(ConnectorAuth) diff --git a/backend/connector_auth/apps.py b/backend/connector_auth/apps.py new file mode 100644 index 000000000..6925d9844 --- /dev/null +++ b/backend/connector_auth/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ConnectorAuthConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "connector_auth" diff --git a/backend/connector_auth/constants.py b/backend/connector_auth/constants.py new file mode 100644 index 000000000..886968d87 --- /dev/null +++ b/backend/connector_auth/constants.py @@ -0,0 +1,18 @@ +class ConnectorAuthKey: + OAUTH_KEY = "oauth-key" + + +class SocialAuthConstants: + UID = "uid" + PROVIDER = "provider" + ACCESS_TOKEN = "access_token" + REFRESH_TOKEN = "refresh_token" + TOKEN_TYPE = "token_type" + AUTH_TIME = "auth_time" + EXPIRES = "expires" + + REFRESH_AFTER_FORMAT = "%d/%m/%Y %H:%M:%S" + REFRESH_AFTER = "refresh_after" # Timestamp to refresh tokens after + + GOOGLE_OAUTH = "google-oauth2" + GOOGLE_TOKEN_EXPIRY_FORMAT = "%d/%m/%Y %H:%M:%S" diff --git a/backend/connector_auth/exceptions.py b/backend/connector_auth/exceptions.py new file mode 100644 index 000000000..603bcc8d9 --- /dev/null +++ b/backend/connector_auth/exceptions.py @@ -0,0 +1,31 @@ +from typing import Optional + +from rest_framework.exceptions import APIException + + +class CacheMissException(APIException): + status_code = 404 + default_detail = "Key doesn't exist." + + +class EnrichConnectorMetadataException(APIException): + status_code = 500 + default_detail = "Connector metadata could not be enriched" + + +class MissingParamException(APIException): + status_code = 400 + default_detail = "Bad request, missing parameter." + + def __init__( + self, + code: Optional[str] = None, + param: Optional[str] = None, + ) -> None: + detail = f"Bad request, missing parameter: {param}" + super().__init__(detail, code) + + +class KeyNotConfigured(APIException): + status_code = 500 + default_detail = "Key is not configured correctly" diff --git a/backend/connector_auth/migrations/0001_initial.py b/backend/connector_auth/migrations/0001_initial.py new file mode 100644 index 000000000..19a702bec --- /dev/null +++ b/backend/connector_auth/migrations/0001_initial.py @@ -0,0 +1,54 @@ +# Generated by Django 4.2.1 on 2024-01-23 11:18 + +import uuid + +import django.db.models.deletion +import social_django.storage +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="ConnectorAuth", + fields=[ + ("provider", models.CharField(max_length=32)), + ("uid", models.CharField(db_index=True, max_length=255)), + ("extra_data", models.JSONField(default=dict)), + ("created", models.DateTimeField(auto_now_add=True)), + ("modified", models.DateTimeField(auto_now=True)), + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "user", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="connector_auth", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + bases=(models.Model, social_django.storage.DjangoUserMixin), + ), + migrations.AddConstraint( + model_name="connectorauth", + constraint=models.UniqueConstraint( + fields=("provider", "uid"), name="unique_provider_uid" + ), + ), + ] diff --git a/backend/connector_auth/migrations/__init__.py b/backend/connector_auth/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/connector_auth/models.py b/backend/connector_auth/models.py new file mode 100644 index 000000000..bc3058a6a --- /dev/null +++ b/backend/connector_auth/models.py @@ -0,0 +1,135 @@ +import logging +import uuid +from typing import Any + +from account.models import User +from connector_auth.constants import SocialAuthConstants +from connector_auth.pipeline.google import GoogleAuthHelper +from django.db import models +from django.db.models.query import QuerySet +from rest_framework.request import Request +from social_django.fields import JSONField +from social_django.models import AbstractUserSocialAuth, DjangoStorage +from social_django.strategy import DjangoStrategy + +logger = logging.getLogger(__name__) + + +class ConnectorAuthManager(models.Manager): + def get_queryset(self) -> QuerySet: + queryset = super().get_queryset() + # TODO PAN-83: Decrypt here + # for obj in queryset: + # logger.info(f"Decrypting extra_data: {obj.extra_data}") + + return queryset + + +class ConnectorAuth(AbstractUserSocialAuth): + """Social Auth association model, stores tokens. + The relation with `account.User` is only for the library to work + and should be NOT be used to access the secrets. + Use the following static methods instead + ``` + @classmethod + def get_social_auth(cls, provider, id): + + @classmethod + def create_social_auth(cls, user, uid, provider): + ``` + """ + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + user = models.ForeignKey( + User, related_name="connector_auth", on_delete=models.SET_NULL, null=True + ) + + def __str__(self) -> str: + return f"ConnectorAuth(provider: {self.provider}, uid: {self.uid})" + + def save(self, *args: Any, **kwargs: Any) -> Any: + # TODO PAN-83: Encrypt here + # logger.info(f"Encrypting extra_data: {self.extra_data}") + return super().save(*args, **kwargs) + + def set_extra_data(self, extra_data=None): # type: ignore + ConnectorAuth.check_credential_format(extra_data) + if extra_data[SocialAuthConstants.PROVIDER] == SocialAuthConstants.GOOGLE_OAUTH: + extra_data = GoogleAuthHelper.enrich_connector_metadata(extra_data) + return super().set_extra_data(extra_data) + + def refresh_token(self, strategy, *args, **kwargs): # type: ignore + """Override of Python Social Auth (PSA)'s refresh_token functionality + to store uid, provider.""" + token = self.extra_data.get("refresh_token") or self.extra_data.get( + "access_token" + ) + backend = self.get_backend_instance(strategy) + if token and backend and hasattr(backend, "refresh_token"): + response = backend.refresh_token(token, *args, **kwargs) + extra_data = backend.extra_data(self, self.uid, response, self.extra_data) + extra_data[SocialAuthConstants.PROVIDER] = backend.name + extra_data[SocialAuthConstants.UID] = self.uid + if self.set_extra_data(extra_data): # type: ignore + self.save() + + def get_and_refresh_tokens(self, request: Request = None) -> tuple[JSONField, bool]: + """Uses Social Auth's ability to refresh tokens if necessary. + + Returns: + Tuple[JSONField, bool]: JSONField of connector metadata + and flag indicating if tokens were refreshed + """ + # To avoid circular dependency error on import + from social_django.utils import load_strategy + + refreshed_token = False + strategy: DjangoStrategy = load_strategy(request=request) + existing_access_token = self.access_token + new_access_token = self.get_access_token(strategy) + if new_access_token != existing_access_token: + refreshed_token = True + related_connector_instances = self.connectorinstance_set.all() + for connector_instance in related_connector_instances: + connector_instance.connector_metadata = self.extra_data + connector_instance.save() + logger.info( + f"Refreshed access token for connector {connector_instance.id}, " + f"provider: {self.provider}, uid: {self.uid}" + ) + + return self.extra_data, refreshed_token + + @staticmethod + def check_credential_format( + oauth_credentials: dict[str, str], raise_exception: bool = True + ) -> bool: + if ( + SocialAuthConstants.PROVIDER in oauth_credentials + and SocialAuthConstants.UID in oauth_credentials + ): + return True + else: + if raise_exception: + raise ValueError( + "Auth credential should have provider, uid and connector guid" + ) + return False + + objects = ConnectorAuthManager() + + class Meta: + app_label = "connector_auth" + constraints = [ + models.UniqueConstraint( + fields=[ + "provider", + "uid", + ], + name="unique_provider_uid", + ), + ] + + +class ConnectorDjangoStorage(DjangoStorage): + user = ConnectorAuth diff --git a/backend/connector_auth/pipeline/common.py b/backend/connector_auth/pipeline/common.py new file mode 100644 index 000000000..5f5861bbf --- /dev/null +++ b/backend/connector_auth/pipeline/common.py @@ -0,0 +1,110 @@ +import logging +from typing import Any, Optional + +from account.models import User +from connector_auth.constants import ConnectorAuthKey, SocialAuthConstants +from connector_auth.models import ConnectorAuth +from connector_auth.pipeline.google import GoogleAuthHelper +from django.conf import settings +from django.core.cache import cache +from rest_framework.exceptions import PermissionDenied +from social_core.backends.oauth import BaseOAuth2 + +logger = logging.getLogger(__name__) + + +def check_user_exists(backend: BaseOAuth2, user: User, **kwargs: Any) -> dict[str, str]: + """Checks if user is authenticated (will be handled in auth middleware, + present as a fail safe) + + Args: + user (account.User): User model + + Raises: + PermissionDenied: Unauthorized user + + Returns: + dict: Carrying response details for auth pipeline + """ + if not user: + raise PermissionDenied(backend) + return {**kwargs} + + +def cache_oauth_creds( + backend: BaseOAuth2, + details: dict[str, str], + response: dict[str, str], + uid: str, + user: User, + *args: Any, + **kwargs: Any, +) -> dict[str, str]: + """Used to cache the extra data JSON in redis against a key. + + This contains the access and refresh token along with details + regarding expiry, uid (unique ID given by provider) and provider. + """ + cache_key = kwargs.get("cache_key") or backend.strategy.session_get( + settings.SOCIAL_AUTH_FIELDS_STORED_IN_SESSION[0], ConnectorAuthKey.OAUTH_KEY + ) + extra_data = backend.extra_data(user, uid, response, details, *args, **kwargs) + extra_data[SocialAuthConstants.PROVIDER] = backend.name + extra_data[SocialAuthConstants.UID] = uid + + if backend.name == SocialAuthConstants.GOOGLE_OAUTH: + extra_data = GoogleAuthHelper.enrich_connector_metadata(extra_data) + + cache.set( + cache_key, + extra_data, + int(settings.SOCIAL_AUTH_EXTRA_DATA_EXPIRATION_TIME_IN_SECOND), + ) + return {**kwargs} + + +class ConnectorAuthHelper: + @staticmethod + def get_oauth_creds_from_cache( + cache_key: str, delete_key: bool = True + ) -> Optional[dict[str, str]]: + """Retrieves oauth credentials from the cache. + + Args: + cache_key (str): Key to obtain credentials from + + Returns: + Optional[dict[str,str]]: Returns credentials. None if it doesn't exist + """ + oauth_creds: dict[str, str] = cache.get(cache_key) + if delete_key: + cache.delete(cache_key) + return oauth_creds + + @staticmethod + def get_or_create_connector_auth( + oauth_credentials: dict[str, str], user: User = None # type: ignore + ) -> ConnectorAuth: + """Gets or creates a ConnectorAuth object. + + Args: + user (User): Used while creation, can be removed if not required + oauth_credentials (dict[str,str]): Needs to have provider and uid + + Returns: + ConnectorAuth: Object for the respective provider/uid + """ + ConnectorAuth.check_credential_format(oauth_credentials) + provider = oauth_credentials[SocialAuthConstants.PROVIDER] + uid = oauth_credentials[SocialAuthConstants.UID] + connector_oauth: ConnectorAuth = ConnectorAuth.get_social_auth( + provider=provider, uid=uid + ) + if not connector_oauth: + connector_oauth = ConnectorAuth.create_social_auth( + user, uid=uid, provider=provider + ) + + # TODO: Remove User's related manager access to ConnectorAuth + connector_oauth.set_extra_data(oauth_credentials) # type: ignore + return connector_oauth diff --git a/backend/connector_auth/pipeline/google.py b/backend/connector_auth/pipeline/google.py new file mode 100644 index 000000000..8da2a3ec6 --- /dev/null +++ b/backend/connector_auth/pipeline/google.py @@ -0,0 +1,33 @@ +from datetime import datetime, timedelta + +from unstract.connectors.filesystems.google_drive.constants import GDriveConstants + +from connector_auth.constants import SocialAuthConstants as AuthConstants +from connector_auth.exceptions import EnrichConnectorMetadataException +from connector_processor.constants import ConnectorKeys + + +class GoogleAuthHelper: + @staticmethod + def enrich_connector_metadata(kwargs: dict[str, str]) -> dict[str, str]: + token_expiry: datetime = datetime.now() + auth_time = kwargs.get(AuthConstants.AUTH_TIME) + expires = kwargs.get(AuthConstants.EXPIRES) + if auth_time and expires: + reference = datetime.utcfromtimestamp(float(auth_time)) + token_expiry = reference + timedelta(seconds=float(expires)) + else: + raise EnrichConnectorMetadataException + # Used by GDrive FS, apart from ACCESS_TOKEN and REFRESH_TOKEN + kwargs[GDriveConstants.TOKEN_EXPIRY] = token_expiry.strftime( + AuthConstants.GOOGLE_TOKEN_EXPIRY_FORMAT + ) + + # Used by Unstract + kwargs[ + ConnectorKeys.PATH + ] = GDriveConstants.ROOT_PREFIX # Acts as a prefix for all paths + kwargs[AuthConstants.REFRESH_AFTER] = token_expiry.strftime( + AuthConstants.REFRESH_AFTER_FORMAT + ) + return kwargs diff --git a/backend/connector_auth/urls.py b/backend/connector_auth/urls.py new file mode 100644 index 000000000..55337ad20 --- /dev/null +++ b/backend/connector_auth/urls.py @@ -0,0 +1,21 @@ +from django.urls import include, path, re_path +from rest_framework.urlpatterns import format_suffix_patterns + +from .views import ConnectorAuthViewSet + +connector_auth_cache = ConnectorAuthViewSet.as_view( + { + "get": "cache_key", + } +) + +urlpatterns = format_suffix_patterns( + [ + path("oauth/", include("social_django.urls", namespace="social")), + re_path( + "^oauth/cache-key/(?P.+)$", + connector_auth_cache, + name="connector-cache", + ), + ] +) diff --git a/backend/connector_auth/views.py b/backend/connector_auth/views.py new file mode 100644 index 000000000..c944d3565 --- /dev/null +++ b/backend/connector_auth/views.py @@ -0,0 +1,45 @@ +import logging +import uuid + +from connector_auth.constants import SocialAuthConstants +from connector_auth.exceptions import KeyNotConfigured +from django.conf import settings +from rest_framework import status, viewsets +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning + +logger = logging.getLogger(__name__) + + +class ConnectorAuthViewSet(viewsets.ViewSet): + """Contains methods for Connector related authentication.""" + + versioning_class = URLPathVersioning + + def cache_key( + self: "ConnectorAuthViewSet", request: Request, backend: str + ) -> Response: + if backend == SocialAuthConstants.GOOGLE_OAUTH and ( + settings.SOCIAL_AUTH_GOOGLE_OAUTH2_KEY is None + or settings.SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET is None + ): + msg = ( + f"Keys not configured for {backend}, add env vars " + f"`GOOGLE_OAUTH2_KEY` and `GOOGLE_OAUTH2_SECRET`." + ) + logger.warn(msg) + raise KeyNotConfigured( + msg + + "\nRefer https://developers.google.com/identity/protocols/oauth2#1.-obtain-oauth-2.0-credentials-from-the-dynamic_data.setvar.console_name-." # noqa + ) + + random = str(uuid.uuid4()) + user_id = request.user.user_id + org_id = request.org_id + cache_key = f"oauth:{org_id}|{user_id}|{backend}|{random}" + logger.info(f"Generated cache key: {cache_key}") + return Response( + status=status.HTTP_200_OK, + data={"cache_key": f"{cache_key}"}, + ) diff --git a/backend/connector_processor/__init__.py b/backend/connector_processor/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/connector_processor/connector_processor.py b/backend/connector_processor/connector_processor.py new file mode 100644 index 000000000..cf2f55365 --- /dev/null +++ b/backend/connector_processor/connector_processor.py @@ -0,0 +1,167 @@ +# mypy: ignore-errors +import json +import logging +from typing import Any, Optional + +from connector.constants import ConnectorInstanceKey as CIKey +from connector_auth.constants import ConnectorAuthKey +from connector_auth.pipeline.common import ConnectorAuthHelper +from connector_processor.constants import ConnectorKeys +from connector_processor.exceptions import ( + InternalServiceError, + InValidConnectorId, + InValidConnectorMode, + OAuthTimeOut, + TestConnectorException, + TestConnectorInputException, +) +from unstract.connectors.base import UnstractConnector +from unstract.connectors.connectorkit import Connectorkit +from unstract.connectors.enums import ConnectorMode +from unstract.connectors.exceptions import ConnectorError +from unstract.connectors.filesystems.ucs import UnstractCloudStorage + +logger = logging.getLogger(__name__) + + +def fetch_connectors_by_key_value( + key: str, value: Any, connector_mode: Optional[ConnectorMode] = None +) -> list[UnstractConnector]: + """Fetches a list of connectors that have an attribute matching key and + value.""" + logger.info(f"Fetching connector list for {key} with {value}") + connector_kit = Connectorkit() + connectors = connector_kit.get_connectors_list(mode=connector_mode) + return [iterate for iterate in connectors if iterate[key] == value] + + +class ConnectorProcessor: + @staticmethod + def get_json_schema(connector_id: str) -> dict: + """Function to return JSON Schema for Connectors.""" + schema_details: dict = {} + if connector_id == UnstractCloudStorage.get_id(): + return schema_details + updated_connectors = fetch_connectors_by_key_value( + ConnectorKeys.ID, connector_id + ) + if len(updated_connectors) != 0: + connector = updated_connectors[0] + schema_details[ConnectorKeys.OAUTH] = connector.get( + ConnectorKeys.OAUTH + ) + schema_details[ConnectorKeys.SOCIAL_AUTH_URL] = connector.get( + ConnectorKeys.SOCIAL_AUTH_URL + ) + try: + schema_details[ConnectorKeys.JSON_SCHEMA] = json.loads( + connector.get(ConnectorKeys.JSON_SCHEMA) + ) + except Exception as exc: + logger.error(f"Error occurred while parsing JSON Schema: {exc}") + raise InternalServiceError() + else: + logger.error( + f"Invalid connector Id : {connector_id} " + f"while fetching " + f"JSON Schema" + ) + raise InValidConnectorId() + return schema_details + + @staticmethod + def get_all_supported_connectors( + type: str, connector_mode: Optional[ConnectorMode] = None + ) -> list[dict]: + """Function to return list of all supported connectors except PCS.""" + supported_connectors = [] + updated_connectors = [] + if type == ConnectorKeys.INPUT: + updated_connectors = fetch_connectors_by_key_value( + ConnectorKeys.CAN_READ, True, connector_mode=connector_mode + ) + if type == ConnectorKeys.OUTPUT: + updated_connectors = fetch_connectors_by_key_value( + ConnectorKeys.CAN_WRITE, True, connector_mode=connector_mode + ) + + for each_connector in updated_connectors: + supported_connectors.append( + { + ConnectorKeys.ID: each_connector.get(ConnectorKeys.ID), + ConnectorKeys.NAME: each_connector.get(ConnectorKeys.NAME), + ConnectorKeys.DESCRIPTION: each_connector.get( + ConnectorKeys.DESCRIPTION + ), + ConnectorKeys.ICON: each_connector.get(ConnectorKeys.ICON), + CIKey.CONNECTOR_MODE: each_connector.get( + CIKey.CONNECTOR_MODE + ).name, + } + ) + + return supported_connectors + + @staticmethod + def test_connectors(connector_id: str, cred_string: dict[str, Any]) -> bool: + logger.info(f"Testing connector: {connector_id}") + connector: dict[str, Any] = fetch_connectors_by_key_value( + ConnectorKeys.ID, connector_id + )[0] + if connector.get(ConnectorKeys.OAUTH): + try: + oauth_key = cred_string.get(ConnectorAuthKey.OAUTH_KEY) + cred_string = ConnectorAuthHelper.get_oauth_creds_from_cache( + cache_key=oauth_key, delete_key=False + ) + except Exception as exc: + logger.error( + f"Error while testing file based OAuth supported " + f"connectors: {exc}" + ) + raise OAuthTimeOut() + + try: + connector_impl = Connectorkit().get_connector_by_id( + connector_id, cred_string + ) + test_result = connector_impl.test_credentials() + logger.info(f"{connector_id} test result: {test_result}") + return test_result + except ConnectorError as e: + logger.error(f"Error while testing {connector_id}: {e}") + raise TestConnectorInputException(core_err=e) + except Exception as e: + logger.error(f"Error while testing {connector_id}: {e}") + raise TestConnectorException + + def get_connector_data_with_key(connector_id: str, key_value: str) -> Any: + """Generic Function to get connector data with provided key.""" + updated_connectors = fetch_connectors_by_key_value("id", connector_id) + if len(updated_connectors) == 0: + logger.error( + f"Invalid connector ID {connector_id} while invoking utility" + ) + raise InValidConnectorId() + return fetch_connectors_by_key_value("id", connector_id)[0].get( + key_value + ) + + @staticmethod + def validate_connector_mode(connector_mode: str) -> ConnectorMode: + """Validate the connector mode. + + Parameters: + - connector_mode (str): The connector mode to validate. + + Returns: + - ConnectorMode: The validated connector mode. + + Raises: + - InValidConnectorMode: If the connector mode is not valid. + """ + try: + connector_mode = ConnectorMode(connector_mode) + except ValueError: + raise InValidConnectorMode + return connector_mode diff --git a/backend/connector_processor/constants.py b/backend/connector_processor/constants.py new file mode 100644 index 000000000..2fbb0fea7 --- /dev/null +++ b/backend/connector_processor/constants.py @@ -0,0 +1,27 @@ +class ConnectorKeys: + CLASS = "class" + MODULE = "module" + PATH = "path" + IS_VALID = "is_valid" + ID = "id" + OAUTH = "oauth" + SOCIAL_AUTH_URL = "python_social_auth_backend" + JSON_SCHEMA = "json_schema" + INPUT = "INPUT" + OUTPUT = "OUTPUT" + CAN_READ = "can_read" + CAN_WRITE = "can_write" + NAME = "name" + DESCRIPTION = "description" + ICON = "icon" + EXTRA_DATA = "extra_data" + REQUIRED = "required" + CONNECTOR_METADATA = "connector_metadata" + CONNECTOR_ID = "connector_id" + TYPE = "type" + PROJECT = "project" + CONNECTOR_MODE = "connector_mode" + + +class Connector: + API_STORAGE = "api|6d102906-9f17-4faa-92f0-bdc6bb07e4e1" diff --git a/backend/connector_processor/exceptions.py b/backend/connector_processor/exceptions.py new file mode 100644 index 000000000..77ddeea64 --- /dev/null +++ b/backend/connector_processor/exceptions.py @@ -0,0 +1,50 @@ +from backend.exceptions import UnstractBaseException +from rest_framework.exceptions import APIException +from unstract.connectors.exceptions import ConnectorError + + +class IdIsMandatory(APIException): + status_code = 400 + default_detail = "ID is Mandatory." + + +class InValidType(APIException): + status_code = 400 + default_detail = "Type is not Valid." + + +class InValidConnectorMode(APIException): + status_code = 400 + default_detail = "Connector mode is not Valid." + + +class InValidConnectorId(APIException): + status_code = 400 + default_detail = "Connector ID is not Valid." + + +class JSONParseException(APIException): + status_code = 500 + default_detail = "Exception occured while Parsing JSON Schema." + + +class OAuthTimeOut(APIException): + status_code = 408 + default_detail = "Timed Out. Please re authenticate." + + +class InternalServiceError(APIException): + status_code = 500 + default_detail = "Internal Service error" + + +class TestConnectorException(APIException): + status_code = 500 + default_detail = "Error while testing connector." + + +class TestConnectorInputException(UnstractBaseException): + def __init__(self, core_err: ConnectorError) -> None: + super().__init__(detail=core_err.message, core_err=core_err) + self.default_detail = core_err.message + self.status_code = 400 diff --git a/backend/connector_processor/serializers.py b/backend/connector_processor/serializers.py new file mode 100644 index 000000000..f1d1a69e3 --- /dev/null +++ b/backend/connector_processor/serializers.py @@ -0,0 +1,7 @@ +from backend.constants import FieldLengthConstants as FLC +from rest_framework import serializers + + +class TestConnectorSerializer(serializers.Serializer): + connector_id = serializers.CharField(max_length=FLC.CONNECTOR_ID_LENGTH) + connector_metadata = serializers.JSONField() diff --git a/backend/connector_processor/urls.py b/backend/connector_processor/urls.py new file mode 100644 index 000000000..95d693124 --- /dev/null +++ b/backend/connector_processor/urls.py @@ -0,0 +1,16 @@ +from connector_processor.views import ConnectorViewSet +from django.urls import path + +from . import views + +connector_test = ConnectorViewSet.as_view({"post": "test"}) + +urlpatterns = [ + path("connector_schema/", views.get_connector_schema, name="get_connector_schema"), + path( + "supported_connectors/", + views.get_supported_connectors, + name="get_supported_connectors", + ), + path("test_connectors/", connector_test, name="connector-test"), +] diff --git a/backend/connector_processor/views.py b/backend/connector_processor/views.py new file mode 100644 index 000000000..ada158542 --- /dev/null +++ b/backend/connector_processor/views.py @@ -0,0 +1,84 @@ +from connector.constants import ConnectorInstanceKey as CIKey +from connector_processor.connector_processor import ConnectorProcessor +from connector_processor.constants import ConnectorKeys +from connector_processor.exceptions import IdIsMandatory, InValidType +from connector_processor.serializers import TestConnectorSerializer +from django.http.request import HttpRequest +from django.http.response import HttpResponse +from rest_framework import status +from rest_framework.decorators import api_view +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.serializers import Serializer +from rest_framework.versioning import URLPathVersioning +from rest_framework.viewsets import GenericViewSet + + +@api_view(("GET",)) +def get_connector_schema(request: HttpRequest) -> HttpResponse: + if request.method == "GET": + connector_name = request.GET.get(ConnectorKeys.ID) + if connector_name is None or connector_name == "": + raise IdIsMandatory() + json_schema = ConnectorProcessor.get_json_schema( + connector_id=connector_name + ) + return Response(data=json_schema, status=status.HTTP_200_OK) + + +@api_view(("GET",)) +def get_supported_connectors(request: HttpRequest) -> HttpResponse: + """Retrieves a list of supported connectors based on the provided connector + type and mode. + + Args: + request (HttpRequest): The HTTP request object. + + Returns: + HttpResponse: The HTTP response containing the list of supported + connectors in JSON format. + """ + if request.method == "GET": + connector_type = request.GET.get(ConnectorKeys.TYPE) + connector_mode = request.GET.get(ConnectorKeys.CONNECTOR_MODE) + if connector_mode: + connector_mode = ConnectorProcessor.validate_connector_mode( + connector_mode + ) + + if ( + connector_type == ConnectorKeys.INPUT + or connector_type == ConnectorKeys.OUTPUT + ): + json_schema = ConnectorProcessor.get_all_supported_connectors( + type=connector_type, connector_mode=connector_mode + ) + return Response(json_schema, status=status.HTTP_200_OK) + else: + raise InValidType + + +class ConnectorViewSet(GenericViewSet): + versioning_class = URLPathVersioning + serializer_class = TestConnectorSerializer + + def get_serializer_class(self) -> Serializer: + if self.action == "test": + return TestConnectorSerializer + return super().get_serializer_class() + + def test(self, request: Request) -> Response: + """Tests the connector against the credentials passed.""" + serializer: TestConnectorSerializer = self.get_serializer( + data=request.data + ) + serializer.is_valid(raise_exception=True) + connector_id = serializer.validated_data.get(ConnectorKeys.CONNECTOR_ID) + cred_string = serializer.validated_data.get(CIKey.CONNECTOR_METADATA) + test_result = ConnectorProcessor.test_connectors( + connector_id=connector_id, cred_string=cred_string + ) + return Response( + {ConnectorKeys.IS_VALID: test_result}, + status=status.HTTP_200_OK, + ) diff --git a/backend/cron_expression_generator/__init__.py b/backend/cron_expression_generator/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/cron_expression_generator/constants.py b/backend/cron_expression_generator/constants.py new file mode 100644 index 000000000..77c33c2aa --- /dev/null +++ b/backend/cron_expression_generator/constants.py @@ -0,0 +1,7 @@ +class CronKeys: + CRON_STRING = "cron_string" + FREQUENCY = "frequency" + SUMMARY = "summary" + # For caching + CRON_CACHE_STATUS = "is_cleared" + ORG_ID = "org_id" diff --git a/backend/cron_expression_generator/descriptor.py b/backend/cron_expression_generator/descriptor.py new file mode 100644 index 000000000..6b1aace6d --- /dev/null +++ b/backend/cron_expression_generator/descriptor.py @@ -0,0 +1,33 @@ +import logging + +from cron_descriptor import CasingTypeEnum, ExpressionDescriptor, FormatException +from cron_expression_generator.exceptions import CronDescriptionError + +logger = logging.getLogger(__name__) + + +class CronDescriptor: + """Describes a cron deterministically with `cron-expression-description`""" + + @staticmethod + def describe_cron(cron: str) -> str: + """Given a cron string, gives a human readable summary of it. + + Args: + cron (str): Cron to summarize + + Returns: + str: Human readable summary of the cron string + """ + summary = "" + logger.info(f"Describing cron: {cron}") + try: + descriptor = ExpressionDescriptor( + expression=cron, + casing_type=CasingTypeEnum.Sentence, + use_24hour_time_format=True, + ) + summary = descriptor.get_full_description() + except FormatException: + raise CronDescriptionError("Incorrect cron string format") + return summary diff --git a/backend/cron_expression_generator/exceptions.py b/backend/cron_expression_generator/exceptions.py new file mode 100644 index 000000000..ad3f4cba6 --- /dev/null +++ b/backend/cron_expression_generator/exceptions.py @@ -0,0 +1,11 @@ +from rest_framework.exceptions import APIException + + +class CronGenerationError(APIException): + status_code = 424 + default_detail = "Error generating schedule." + + +class CronDescriptionError(APIException): + status_code = 500 + default_detail = "Error while summarizing schedule." diff --git a/backend/cron_expression_generator/generator.py b/backend/cron_expression_generator/generator.py new file mode 100644 index 000000000..c20ccd826 --- /dev/null +++ b/backend/cron_expression_generator/generator.py @@ -0,0 +1,59 @@ +import logging +from typing import Optional + +from backend.exceptions import LLMHelperError +from unstract.core.llm_helper.enums import LLMResult, PromptContext +from unstract.core.llm_helper.llm_helper import LLMHelper +from unstract.core.llm_helper.models import LLMResponse + +logger = logging.getLogger(__name__) + + +class CronGenerator: + """Uses LLM to generate a cron string for a user input of frequency.""" + + @staticmethod + def generate_cron(frequency: str, cache_key_prefix: Optional[str] = None) -> str: + """Generates cron for a user provided description of frequency. + + Uses LLM to prefix the user input with a prompt template and generate cron + + Args: + frequency (str): User provided input + cache_key (Optional[str], optional): Key to cache against. Defaults to None. + + Returns: + str: Generated cron string + """ + cron_response: LLMResponse + logging.info(f"Generating cron for '{frequency}'") + use_cache = True + if cache_key_prefix is None: + use_cache = False + cron_llm = LLMHelper( + cache_key_prefix=cache_key_prefix, + prompt_context=PromptContext.GENERATE_CRON_STRING, + ) + cron_response = cron_llm.get_response_from_llm( + prompt=frequency, use_cache=use_cache + ) + if use_cache is False: + logging.info( + f"Cron generation LLM call - Elapsed: {cron_response.time_taken:.3f}s" + ) + if cron_response.result.value == LLMResult.NOK.value: + raise LLMHelperError(cron_response.output) + output: str = cron_response.output + return output + + @staticmethod + def clear_cron_cache(cache_key_prefix: str) -> bool: + cleared_count = 0 + cron_llm = LLMHelper( + cache_key_prefix=cache_key_prefix, + prompt_context=PromptContext.GENERATE_CRON_STRING, + ) + cleared_count = cron_llm.clear_cache() + if cleared_count == -1: + return False + return True diff --git a/backend/cron_expression_generator/serializer.py b/backend/cron_expression_generator/serializer.py new file mode 100644 index 000000000..70cb22fc3 --- /dev/null +++ b/backend/cron_expression_generator/serializer.py @@ -0,0 +1,12 @@ +import logging + +from backend.constants import FieldLengthConstants as FLC +from rest_framework import serializers + +logger = logging.getLogger(__name__) + + +class CronGenerateSerializer(serializers.Serializer): + frequency = serializers.CharField(max_length=FLC.CRON_LENGTH, required=False) + cron_string = serializers.CharField(max_length=FLC.CRON_LENGTH, required=False) + summary = serializers.CharField(max_length=FLC.CRON_LENGTH, required=False) diff --git a/backend/cron_expression_generator/urls.py b/backend/cron_expression_generator/urls.py new file mode 100644 index 000000000..c0e05c482 --- /dev/null +++ b/backend/cron_expression_generator/urls.py @@ -0,0 +1,13 @@ +from cron_expression_generator.views import CronViewSet +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns + +cron_generate = CronViewSet.as_view({"post": "generate"}) +cron_clear_cache = CronViewSet.as_view({"get": "clear_cron_cache"}) + +urlpatterns = format_suffix_patterns( + [ + path("cron/generate/", cron_generate, name="cron-generate"), + path("cron/clear-cache/", cron_clear_cache, name="cron-clear-cache"), + ] +) diff --git a/backend/cron_expression_generator/views.py b/backend/cron_expression_generator/views.py new file mode 100644 index 000000000..897dc084d --- /dev/null +++ b/backend/cron_expression_generator/views.py @@ -0,0 +1,64 @@ +import logging + +from cron_expression_generator.constants import CronKeys +from cron_expression_generator.descriptor import CronDescriptor +from cron_expression_generator.exceptions import ( + CronDescriptionError, + CronGenerationError, +) +from cron_expression_generator.generator import CronGenerator +from cron_expression_generator.serializer import CronGenerateSerializer +from rest_framework import status, viewsets +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning + +logger = logging.getLogger(__name__) + + +class CronViewSet(viewsets.GenericViewSet, viewsets.mixins.CreateModelMixin): + versioning_class = URLPathVersioning + serializer_class = CronGenerateSerializer + + def generate(self, request: Request) -> Response: + """For an input of `frequency`, generates the cron string and summary. + + For an input of `cron_string`, generates the summary alone. + """ + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + frequency_from_user = serializer.validated_data.get(CronKeys.FREQUENCY) + cron_string = serializer.validated_data.get(CronKeys.CRON_STRING) + if frequency_from_user: + cache_key_prefix = request.org_id + try: + cron_string = CronGenerator.generate_cron( + frequency=frequency_from_user, cache_key_prefix=cache_key_prefix + ) + serializer.validated_data[CronKeys.CRON_STRING] = cron_string + except Exception as e: + logger.error( + f"Error generating cron for input: '{frequency_from_user}'" + f", error: {e}" + ) + raise CronGenerationError() + + if cron_string: + try: + serializer.validated_data[ + CronKeys.SUMMARY + ] = CronDescriptor.describe_cron(cron=cron_string) + except Exception as e: + logger.error( + f"Error describing cron for input: '{cron_string}', error: {e}" + ) + raise CronDescriptionError() + return Response(serializer.validated_data, status=status.HTTP_200_OK) + + def clear_cron_cache(self, request: Request) -> Response: + """Clears the cache used for cron generation.""" + cache_key_prefix = request.query_params.get(CronKeys.ORG_ID, request.org_id) + is_cleared = CronGenerator.clear_cron_cache(cache_key_prefix=cache_key_prefix) + return Response( + {CronKeys.CRON_CACHE_STATUS: is_cleared}, status=status.HTTP_200_OK + ) diff --git a/backend/docs/__init__.py b/backend/docs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/docs/urls.py b/backend/docs/urls.py new file mode 100644 index 000000000..ff6071f25 --- /dev/null +++ b/backend/docs/urls.py @@ -0,0 +1,16 @@ +from django.urls import path +from drf_yasg import openapi +from drf_yasg.views import get_schema_view + +schema_view = get_schema_view( + openapi.Info( + title="Unstract APIs", + default_version="v1", + description="", + ), + public=False, +) + +urlpatterns = [ + path("doc/", schema_view.with_ui("redoc", cache_timeout=0), name="schema-redoc"), +] diff --git a/backend/entrypoint.sh b/backend/entrypoint.sh new file mode 100755 index 000000000..e87c39d93 --- /dev/null +++ b/backend/entrypoint.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +chown -R unstract /data + +su unstract + +cmd=$1 +if [ "$cmd" = "migrate" ]; then + echo "Migration initiated" + .venv/bin/python manage.py migrate +fi + +# NOTE: Leaving below for reference incase required in the future +# python manage.py runserver 0.0.0.0:8000 --insecure +# NOTE updated socket threads +.venv/bin/gunicorn \ + --bind 0.0.0.0:8000 \ + --workers 2 \ + --threads 4 \ + --log-level debug \ + --timeout 600 \ + --access-logfile - \ + --reload \ + backend.wsgi:application diff --git a/backend/feature_flag/__init__.py b/backend/feature_flag/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/feature_flag/admin.py b/backend/feature_flag/admin.py new file mode 100644 index 000000000..846f6b406 --- /dev/null +++ b/backend/feature_flag/admin.py @@ -0,0 +1 @@ +# Register your models here. diff --git a/backend/feature_flag/apps.py b/backend/feature_flag/apps.py new file mode 100644 index 000000000..f9e2801bd --- /dev/null +++ b/backend/feature_flag/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class FeatureFlagsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "feature_flag" diff --git a/backend/feature_flag/migrations/__init__.py b/backend/feature_flag/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/feature_flag/models.py b/backend/feature_flag/models.py new file mode 100644 index 000000000..6b2021999 --- /dev/null +++ b/backend/feature_flag/models.py @@ -0,0 +1 @@ +# Create your models here. diff --git a/backend/feature_flag/urls.py b/backend/feature_flag/urls.py new file mode 100644 index 000000000..288dc1520 --- /dev/null +++ b/backend/feature_flag/urls.py @@ -0,0 +1,12 @@ +"""URL patterns for feature_flags app. + +This module defines the URL patterns for the feature_flags app. +""" +import feature_flag.views as views +from django.urls import path + +urlpatterns = [ + path( + "evaluate/", views.evaluate_feature_flag, name="evaluate_feature_flag" + ), +] diff --git a/backend/feature_flag/views.py b/backend/feature_flag/views.py new file mode 100644 index 000000000..964f0ac4b --- /dev/null +++ b/backend/feature_flag/views.py @@ -0,0 +1,55 @@ +""" + Feature Flag view file +Returns: + evaluate response +""" +import logging + +from rest_framework import status +from rest_framework.decorators import api_view +from rest_framework.request import Request +from rest_framework.response import Response +from unstract.flags.client import EvaluationClient + +logger = logging.getLogger(__name__) + + +@api_view(["POST"]) +def evaluate_feature_flag(request: Request) -> Response: + """Function to evaluate the feature flag. + + To-Do: Refactor to a class based view, use serializers (DRF). + + Args: + request: request object + + Returns: + evaluate response + """ + try: + namespace_key = request.data.get("namespace_key") + flag_key = request.data.get("flag_key") + entity_id = request.data.get("entity_id") + context = request.data.get("context") + + if not namespace_key or not flag_key or not entity_id: + return Response( + {"message": "Request paramteres are missing."}, + status=status.HTTP_400_BAD_REQUEST, + ) + + evaluation_client = EvaluationClient() + response = evaluation_client.boolean_evaluate_feature_flag( + namespace_key=namespace_key, + flag_key=flag_key, + entity_id=entity_id, + context=context, + ) + + return Response({"enabled": response}, status=status.HTTP_200_OK) + except Exception as e: + logger.error("No response from server: %s", e) + return Response( + {"message": "No response from server"}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR, + ) diff --git a/backend/file_management/__init__.py b/backend/file_management/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/file_management/admin.py b/backend/file_management/admin.py new file mode 100644 index 000000000..846f6b406 --- /dev/null +++ b/backend/file_management/admin.py @@ -0,0 +1 @@ +# Register your models here. diff --git a/backend/file_management/api_doc.md b/backend/file_management/api_doc.md new file mode 100644 index 000000000..07eca7cbb --- /dev/null +++ b/backend/file_management/api_doc.md @@ -0,0 +1,40 @@ +# FileManagement APIs + +### List File + +```http +GET /unstract//file?connector_id=&path= +``` + +Sample URL: +> /unstract/org_KIYj2cJ9Yisdewi4/file?connector_id=11&path=/ + +### Download + +```http +GET /unstract//file/download?connector_id=&path= +``` + +Sample URL: +> /unstract/org_KIYj2cJ9Yisdewi4/file/download?connector_id=12&path=root/MaskTwo-design + +### Upload + +```http +POST /unstract//file/upload +``` + +Sample URL: +> /unstract/org_KIYj2cJ9Yisdewi4/file/upload + +- postman [url](https://zip-access-control-team.postman.co/workspace/My-Workspace~53945a45-432a-4093-811e-56d225da5b8c/request/24537488-2967e31d-7f8a-4dc5-8f09-0ab89e98b1c5?ctx=documentation) + +#### Body + +```json +{ + "file": "", + "connector_id": "", + "path": "", +} +``` diff --git a/backend/file_management/apps.py b/backend/file_management/apps.py new file mode 100644 index 000000000..f9430740c --- /dev/null +++ b/backend/file_management/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class FileManagementConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "file_management" diff --git a/backend/file_management/constants.py b/backend/file_management/constants.py new file mode 100644 index 000000000..82c16e045 --- /dev/null +++ b/backend/file_management/constants.py @@ -0,0 +1,5 @@ +class FileInformationKey: + FILE_NAME = "name" + FILE_TYPE = "type" + FILE_LAST_MODIFIED = "LastModified" + FILE_SIZE = "size" diff --git a/backend/file_management/exceptions.py b/backend/file_management/exceptions.py new file mode 100644 index 000000000..b7bf42d22 --- /dev/null +++ b/backend/file_management/exceptions.py @@ -0,0 +1,93 @@ +from typing import Optional + +from rest_framework.exceptions import APIException + +from backend.exceptions import UnstractBaseException + + +class MissingConnectorParams(APIException): + status_code = 400 + default_detail = "Missing params in connector metadata" + + +class ConnectorClassNotFound(APIException): + status_code = 404 + default_detail = "Connector class does not exist" + + +class ConnectorInstanceNotFound(APIException): + status_code = 404 + default_detail = "Connector instance does not exist" + + +class InternalServerError(APIException): + status_code = 500 + default_detail = "Unknown exception" + + +class ConnectorOAuthError(APIException): + status_code = 401 + default_detail = "Unauthorized client during OAuth" + + +class ConnectorApiRequestError(APIException): + status_code = 400 + default_detail = "Failed to stream file" + + +class InvalidFileType(APIException): + status_code = 404 + default_detail = "Invalid file type" + + +class FileListError(UnstractBaseException): + status_code = 500 + default_detail = "Error occured while listing files" + + +class FileNotFound(APIException): + status_code = 404 + default_detail = "Selected file not found in the location." + + +class EnvRequired(APIException): + status_code = 404 + default_detail = "Environment variable not set" + + +class OrgIdNotValid(APIException): + status_code = 400 + default_detail = "Organization ID is not valid" + + +class TenantDirCreationError(APIException): + status_code = 500 + default_detail = "Error while creating a temporary directory for processing" + + +class ValidationError(APIException): + status_code = 400 + default_detail = "Validation Error" + + def __init__( + self, detail: Optional[str] = None, code: Optional[int] = None + ): + if detail is not None: + self.detail = detail + if code is not None: + self.code = code + super().__init__() + + +class FileDeletionFailed(APIException): + status_code = 400 + default_detail = "Unable to delete file." + + def __init__( + self, detail: Optional[str] = None, code: Optional[int] = None + ): + if detail is not None: + self.detail = detail + if code is not None: + self.code = code + super().__init__() diff --git a/backend/file_management/file_management_dto.py b/backend/file_management/file_management_dto.py new file mode 100644 index 000000000..100efe1a4 --- /dev/null +++ b/backend/file_management/file_management_dto.py @@ -0,0 +1,37 @@ +import os +from dataclasses import dataclass +from datetime import datetime +from typing import Any, Optional, Union + +from file_management.constants import FileInformationKey + + +@dataclass +class FileInformation: + name: str + type: str + modified_at: Optional[datetime] + content_type: Optional[str] + size: int + + def __init__( + self, file_info: dict[str, Any], file_content_type: Optional[str] = None + ) -> None: + self.name = os.path.normpath(file_info[FileInformationKey.FILE_NAME]) + self.type = file_info[FileInformationKey.FILE_TYPE] + + modified_at = file_info.get(FileInformationKey.FILE_LAST_MODIFIED) + self.modified_at = ( + self.parse_datetime(modified_at) if modified_at else None + ) + + self.content_type = file_content_type + self.size = file_info[FileInformationKey.FILE_SIZE] + + @staticmethod + def parse_datetime( + dt_string: Optional[Union[str, datetime]] + ) -> Optional[datetime]: + if isinstance(dt_string, str): + return datetime.strptime(dt_string, "%Y-%m-%dT%H:%M:%S.%f%z") + return dt_string diff --git a/backend/file_management/file_management_helper.py b/backend/file_management/file_management_helper.py new file mode 100644 index 000000000..a5808f9a5 --- /dev/null +++ b/backend/file_management/file_management_helper.py @@ -0,0 +1,257 @@ +import base64 +import logging +import mimetypes +import os +from pathlib import Path +from typing import Any + +import magic +from connector.models import ConnectorInstance +from django.conf import settings +from django.http import StreamingHttpResponse +from file_management.exceptions import ( + ConnectorApiRequestError, + ConnectorClassNotFound, + FileDeletionFailed, + FileListError, + FileNotFound, + InvalidFileType, + MissingConnectorParams, + OrgIdNotValid, + TenantDirCreationError, +) +from file_management.file_management_dto import FileInformation +from fsspec import AbstractFileSystem +from pydrive2.files import ApiRequestError + +from unstract.connectors.filesystems import connectors as fs_connectors +from unstract.connectors.filesystems.unstract_file_system import ( + UnstractFileSystem, +) + + +class FileManagerHelper: + logger = logging.getLogger(__name__) + + @staticmethod + def get_file_system(connector: ConnectorInstance) -> UnstractFileSystem: + """Creates the `UnstractFileSystem` for the corresponding connector.""" + metadata = connector.connector_metadata + if connector.connector_id in fs_connectors: + connector = fs_connectors[connector.connector_id]["metadata"][ + "connector" + ] + connector_class: UnstractFileSystem = connector(metadata) + return connector_class + else: + FileManagerHelper.logger.error( + f"Class not Found for {connector.connector_id}" + ) + raise ConnectorClassNotFound + + @staticmethod + def list_files( + file_system: UnstractFileSystem, path: str + ) -> list[FileInformation]: + fs = file_system.get_fsspec_fs() + file_path = f"{path}" + # TODO: Add below logic by checking each connector? + try: + if file_system.path and (not path or path == "/"): + file_path = file_system.path + except AttributeError: + if hasattr(fs, "path") and fs.path and (not path or path == "/"): + file_path = fs.path + except Exception: + FileManagerHelper.logger.error(f"Missing path Atribute in {fs}") + raise MissingConnectorParams() + + try: + return FileManagerHelper.get_files(fs, file_path) + except Exception as e: + FileManagerHelper.logger.error(f"Error listing files: {e}") + raise FileListError() + + @staticmethod + def get_files( + fs: AbstractFileSystem, file_path: str + ) -> list[FileInformation]: + """Iterate through the directories and make a list of + FileInformation.""" + if not file_path.endswith("/"): + file_path += "/" + + files = fs.ls(file_path, detail=True) + file_list = [] + for file_info in files: + file_name = file_info.get("name") + if os.path.normpath(file_path) == os.path.normpath(file_name): + continue + + # Call fs.info() to get file size if its missing + if ( + file_info.get("type") == "file" + and file_info.get("size") is None + ): + file_info = fs.info(file_name) + + file_content_type = file_info.get("ContentType") + if not file_content_type: + file_content_type, _ = mimetypes.guess_type(file_name) + file_list.append(FileInformation(file_info, file_content_type)) + return file_list + + @staticmethod + def download_file( + file_system: UnstractFileSystem, file_path: str + ) -> StreamingHttpResponse: + fs = file_system.get_fsspec_fs() + file_info = fs.info(file_path) + file_name = file_info.get("name") + base_name = os.path.basename(file_name) + + file_content_type = file_info.get("ContentType") + file_type = file_info.get("type") + if file_type != "file": + raise InvalidFileType + try: + if not file_content_type: + file_content_type, _ = mimetypes.guess_type(file_path) + if not file_content_type: + file = fs.open(file_path, "rb", block_size=500) + file_content_type = magic.from_buffer(file.read(), mime=True) + file.close() + + file = fs.open(file_path, "rb") + response = StreamingHttpResponse( + file, content_type=file_content_type + ) + response[ + "Content-Disposition" + ] = f"attachment; filename={base_name}" + return response + except ApiRequestError as exception: + FileManagerHelper.logger.error( + f"ApiRequestError from {file_info} {exception}" + ) + raise ConnectorApiRequestError + + @staticmethod + def upload_file( + file_system: UnstractFileSystem, path: str, file: Any, file_name: str + ) -> None: + fs = file_system.get_fsspec_fs() + + file_path = f"{path}" + try: + if file_system.path and (not path or path == "/"): + file_path = f"{file_system.path}/" + except AttributeError: + if fs.path and (not path or path == "/"): + file_path = f"{fs.path}/" + + file_path = ( + file_path + "/" if not file_path.endswith("/") else file_path + ) + + # adding filename with path + file_path += file_name + with fs.open(file_path, mode="wb") as remote_file: + remote_file.write(file.read()) + + @staticmethod + def fetch_file_contents( + file_system: UnstractFileSystem, file_path: str + ) -> Any: + fs = file_system.get_fsspec_fs() + try: + file_info = fs.info(file_path) + except FileNotFoundError: + raise FileNotFound + + file_content_type = file_info.get("ContentType") + file_type = file_info.get("type") + if file_type != "file": + raise InvalidFileType + try: + if not file_content_type: + file_content_type, _ = mimetypes.guess_type(file_path) + if not file_content_type: + file = fs.open(file_path, "rb", block_size=500) + file_content_type = magic.from_buffer(file.read(), mime=True) + file.close() + + except ApiRequestError as exception: + FileManagerHelper.logger.error( + f"ApiRequestError from {file_info} {exception}" + ) + raise ConnectorApiRequestError + if file_content_type == "application/pdf": + # Read contents of PDF file into a string + with fs.open(file_path, "rb") as file: + encoded_string = base64.b64encode(file.read()) + return encoded_string + + elif file_content_type == "text/plain": + with fs.open(file_path, "r") as file: + FileManagerHelper.logger.info(f"Reading text file: {file_path}") + encoded_string = base64.b64encode(file.read()) + return encoded_string + else: + raise InvalidFileType + + @staticmethod + def delete_file( + file_system: UnstractFileSystem, path: str, file_name: str + ) -> bool: + fs = file_system.get_fsspec_fs() + + file_path = f"{path}" + try: + if file_system.path and (not path or path == "/"): + file_path = f"{file_system.path}/" + except AttributeError: + if fs.path and (not path or path == "/"): + file_path = f"{fs.path}/" + + file_path = ( + file_path + "/" if not file_path.endswith("/") else file_path + ) + + # adding filename with path + file_path += file_name + try: + with fs.open(file_path, mode="wb") as remote_file: + return remote_file.fs.delete(remote_file.path) # type:ignore + except Exception as e: + FileManagerHelper.logger.info(f"Unable to delete file {e}") + raise FileDeletionFailed(f"Unable to delete file {e}") + + @staticmethod + def handle_sub_directory_for_tenants( + org_id: str, user_id: str, tool_id: str, is_create: bool + ) -> str: + """Resolves a directory path meant for a user running prompt studio. + + Args: + org_id (str): Organization ID + user_id (str): User ID + tool_id (str): ID of the prompt studio tool + is_create (bool): Flag to create the directory + + Returns: + str: The absolute path to the directory meant for prompt studio + """ + if not org_id: + raise OrgIdNotValid() + base_path = Path(settings.PROMPT_STUDIO_FILE_PATH) + file_path: Path = base_path / org_id / user_id / tool_id + if is_create: + try: + os.makedirs(file_path, exist_ok=True) + except OSError as e: + FileManagerHelper.logger.error( + f"Error while creating {file_path}: {e}" + ) + raise TenantDirCreationError + return str(file_path) diff --git a/backend/file_management/migrations/__init__.py b/backend/file_management/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/file_management/models.py b/backend/file_management/models.py new file mode 100644 index 000000000..6b2021999 --- /dev/null +++ b/backend/file_management/models.py @@ -0,0 +1 @@ +# Create your models here. diff --git a/backend/file_management/serializer.py b/backend/file_management/serializer.py new file mode 100644 index 000000000..5efa0a665 --- /dev/null +++ b/backend/file_management/serializer.py @@ -0,0 +1,33 @@ +from rest_framework import serializers + + +class FileInfoSerializer(serializers.Serializer): + name = serializers.CharField() + type = serializers.CharField() + modified_at = serializers.CharField() + content_type = serializers.CharField() + size = serializers.FloatField() + + +class FileListRequestSerializer(serializers.Serializer): + connector_id = serializers.UUIDField() + path = serializers.CharField() + + +class FileUploadSerializer(serializers.Serializer): + file = serializers.ListField(child=serializers.FileField(), required=True) + connector_id = serializers.UUIDField() + path = serializers.CharField() + + +class FileUploadIdeSerializer(serializers.Serializer): + file = serializers.ListField(child=serializers.FileField(), required=True) + + +class FileInfoIdeSerializer(serializers.Serializer): + file_name = serializers.CharField() + tool_id = serializers.CharField() + + +class FileListRequestIdeSerializer(serializers.Serializer): + tool_id = serializers.CharField() diff --git a/backend/file_management/tests.py b/backend/file_management/tests.py new file mode 100644 index 000000000..a39b155ac --- /dev/null +++ b/backend/file_management/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/backend/file_management/urls.py b/backend/file_management/urls.py new file mode 100644 index 000000000..709b3795a --- /dev/null +++ b/backend/file_management/urls.py @@ -0,0 +1,64 @@ +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns + +from .views import FileManagementViewSet + +file_list = FileManagementViewSet.as_view( + { + "get": "list", + } +) +file_downlaod = FileManagementViewSet.as_view( + { + "get": "download", + } +) + +file_upload = FileManagementViewSet.as_view( + { + "post": "upload", + } +) +prompt_studio_file_upload = FileManagementViewSet.as_view( + { + "post": "upload_for_ide", + } +) +prompt_studio_fetch_content = FileManagementViewSet.as_view( + { + "get": "fetch_contents_ide", + } +) +prompt_studio_file_list = FileManagementViewSet.as_view( + { + "get": "list_ide", + } +) +file_delete = FileManagementViewSet.as_view( + { + "get": "delete", + } +) +urlpatterns = format_suffix_patterns( + [ + path("file", file_list, name="file-list"), + path("file/download", file_downlaod, name="download"), + path("file/upload", file_upload, name="upload"), + path("file/delete", file_delete, name="delete"), + path( + "prompt-studio/file/upload", + prompt_studio_file_upload, + name="prompt_studio_upload", + ), + path( + "prompt-studio/file/fetch_contents", + prompt_studio_fetch_content, + name="tool_studio_fetch", + ), + path( + "prompt-studio/file", + prompt_studio_file_list, + name="prompt_studio_list", + ), + ] +) diff --git a/backend/file_management/views.py b/backend/file_management/views.py new file mode 100644 index 000000000..a8756595f --- /dev/null +++ b/backend/file_management/views.py @@ -0,0 +1,226 @@ +import logging +import os +from typing import Any + +from connector.models import ConnectorInstance +from django.http import HttpRequest +from file_management.exceptions import ( + ConnectorInstanceNotFound, + ConnectorOAuthError, + FileListError, + InternalServerError, +) +from file_management.file_management_helper import FileManagerHelper +from file_management.serializer import ( + FileInfoIdeSerializer, + FileInfoSerializer, + FileListRequestIdeSerializer, + FileListRequestSerializer, + FileUploadIdeSerializer, + FileUploadSerializer, +) +from oauth2client.client import HttpAccessTokenRefreshError +from rest_framework import serializers, status, viewsets +from rest_framework.decorators import action +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning +from unstract.connectors.exceptions import ConnectorError +from unstract.connectors.filesystems.local_storage.local_storage import ( + LocalStorageFS, +) + +logger = logging.getLogger(__name__) + + +class FileManagementViewSet(viewsets.ModelViewSet): + """FileManagement view. + + Handles GET,POST,PUT,PATCH and DELETE + """ + + versioning_class = URLPathVersioning + queryset = ConnectorInstance.objects.all() + + def get_serializer_class(self) -> serializers.Serializer: + if self.action == "upload": + return FileUploadSerializer + elif self.action == "download": + return FileListRequestSerializer + else: + # Default serializer class + return FileListRequestSerializer + + def list(self, request: HttpRequest) -> Response: + serializer = FileListRequestSerializer(data=request.GET) + + serializer.is_valid(raise_exception=True) + # Query params + id: str = serializer.validated_data.get("connector_id") + path: str = serializer.validated_data.get("path") + try: + connector_instance: ConnectorInstance = ( + ConnectorInstance.objects.get(pk=id) + ) + file_system = FileManagerHelper.get_file_system(connector_instance) + files = FileManagerHelper.list_files(file_system, path) + serializer = FileInfoSerializer(files, many=True) + return Response(serializer.data) + except ConnectorInstance.DoesNotExist: + raise ConnectorInstanceNotFound() + except HttpAccessTokenRefreshError as error: + logger.error( + f"HttpAccessTokenRefreshError thrown\ + from file list, error {error}" + ) + raise ConnectorOAuthError() + except ConnectorError as error: + logger.error( + f"ConnectorError thrown during file list, error {error}" + ) + raise FileListError(core_err=error) + except Exception as error: + logger.error(f"Exception thrown from file list, error {error}") + raise InternalServerError() + + @action(detail=True, methods=["get"]) + def download(self, request: HttpRequest) -> Response: + serializer = FileListRequestSerializer(data=request.GET) + serializer.is_valid(raise_exception=True) + id: str = serializer.validated_data.get("connector_id") + path: str = serializer.validated_data.get("path") + connector_instance: ConnectorInstance = ConnectorInstance.objects.get( + pk=id + ) + file_system = FileManagerHelper.get_file_system(connector_instance) + return FileManagerHelper.download_file(file_system, path) + + @action(detail=True, methods=["post"]) + def upload(self, request: HttpRequest) -> Response: + serializer = FileUploadSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + id: str = serializer.validated_data.get("connector_id") + + path: str = serializer.validated_data.get("path") + uploaded_files: Any = serializer.validated_data.get("file") + connector_instance: ConnectorInstance = ConnectorInstance.objects.get( + pk=id + ) + file_system = FileManagerHelper.get_file_system(connector_instance) + + for uploaded_file in uploaded_files: + file_name = uploaded_file.name + logger.info( + f"Uploading file: {file_name}" + if file_name + else "Uploading file" + ) + FileManagerHelper.upload_file( + file_system, path, uploaded_file, file_name + ) + return Response({"message": "Files are uploaded successfully!"}) + + @action(detail=True, methods=["post"]) + def upload_for_ide(self, request: HttpRequest) -> Response: + print(request.data) + serializer = FileUploadIdeSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + uploaded_files: Any = serializer.validated_data.get("file") + tool_id: str = request.query_params.get("tool_id") + file_path = FileManagerHelper.handle_sub_directory_for_tenants( + request.org_id, + is_create=True, + user_id=request.user.user_id, + tool_id=tool_id, + ) + file_system = LocalStorageFS(settings={"path": file_path}) + for uploaded_file in uploaded_files: + file_name = uploaded_file.name + logger.info( + f"Uploading file: {file_name}" + if file_name + else "Uploading file" + ) + FileManagerHelper.upload_file( + file_system, + file_path, + uploaded_file, + file_name, + ) + return Response({"message": "Files are uploaded successfully!"}) + + @action(detail=True, methods=["get"]) + def fetch_contents_ide(self, request: HttpRequest) -> Response: + serializer = FileInfoIdeSerializer(data=request.GET) + serializer.is_valid(raise_exception=True) + file_name: str = serializer.validated_data.get("file_name") + tool_id: str = serializer.validated_data.get("tool_id") + file_path = ( + file_path + ) = FileManagerHelper.handle_sub_directory_for_tenants( + request.org_id, + is_create=True, + user_id=request.user.user_id, + tool_id=tool_id, + ) + file_system = LocalStorageFS(settings={"path": file_path}) + if not file_path.endswith("/"): + file_path += "/" + file_path += file_name + contents = FileManagerHelper.fetch_file_contents(file_system, file_path) + return Response({"data": contents}, status=status.HTTP_200_OK) + + @action(detail=True, methods=["get"]) + def list_ide(self, request: HttpRequest) -> Response: + serializer = FileListRequestIdeSerializer(data=request.GET) + serializer.is_valid(raise_exception=True) + tool_id: str = serializer.validated_data.get("tool_id") + file_path = FileManagerHelper.handle_sub_directory_for_tenants( + request.org_id, + is_create=True, + user_id=request.user.user_id, + tool_id=tool_id, + ) + file_system = LocalStorageFS(settings={"path": file_path}) + try: + files = FileManagerHelper.list_files(file_system, file_path) + serializer = FileInfoSerializer(files, many=True) + # fetching only the name from path + for file in serializer.data: + file_name = os.path.basename(file.get("name")) + file["name"] = file_name + return Response(serializer.data) + except Exception as error: + logger.error(f"Exception thrown from file list, error {error}") + raise InternalServerError() + + @action(detail=True, methods=["get"]) + def delete(self, request: HttpRequest) -> Response: + serializer = FileInfoIdeSerializer(data=request.GET) + serializer.is_valid(raise_exception=True) + file_name: str = serializer.validated_data.get("file_name") + tool_id: str = serializer.validated_data.get("tool_id") + file_path = FileManagerHelper.handle_sub_directory_for_tenants( + request.org_id, + is_create=False, + user_id=request.user.user_id, + tool_id=tool_id, + ) + path = file_path + if not file_name: + return Response( + {"data": "File deletion failed. File name is mandatory"}, + status=status.HTTP_400_BAD_REQUEST, + ) + file_system = LocalStorageFS(settings={"path": path}) + try: + FileManagerHelper.delete_file(file_system, path, file_name) + return Response( + {"data": "File deleted succesfully."}, + status=status.HTTP_200_OK, + ) + except Exception as exc: + logger.error(f"Exception thrown from file deletion, error {exc}") + return Response( + {"data": "File deletion failed."}, + status=status.HTTP_400_BAD_REQUEST, + ) diff --git a/backend/init.sql b/backend/init.sql new file mode 100644 index 000000000..1463fe23f --- /dev/null +++ b/backend/init.sql @@ -0,0 +1,7 @@ +ALTER ROLE unstract_dev SET client_encoding TO 'utf8'; +ALTER ROLE unstract_dev SET default_transaction_isolation TO 'read committed'; +ALTER ROLE unstract_dev SET timezone TO 'UTC'; +ALTER USER unstract_dev CREATEDB; +GRANT ALL PRIVILEGES ON DATABASE unstract_db TO unstract_dev; +CREATE DATABASE unstract; +CREATE EXTENSION vector; diff --git a/backend/log_events/__init__.py b/backend/log_events/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/log_events/admin.py b/backend/log_events/admin.py new file mode 100644 index 000000000..8c38f3f3d --- /dev/null +++ b/backend/log_events/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/backend/log_events/apps.py b/backend/log_events/apps.py new file mode 100644 index 000000000..5fa52f37c --- /dev/null +++ b/backend/log_events/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class LogEventsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'log_events' diff --git a/backend/log_events/constants.py b/backend/log_events/constants.py new file mode 100644 index 000000000..caa0c78f1 --- /dev/null +++ b/backend/log_events/constants.py @@ -0,0 +1,3 @@ +class LogServerConstants: + USER_INFO="userinfo" + PRIMARY_SUB="primary_sub" \ No newline at end of file diff --git a/backend/log_events/migrations/__init__.py b/backend/log_events/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/log_events/models.py b/backend/log_events/models.py new file mode 100644 index 000000000..71a836239 --- /dev/null +++ b/backend/log_events/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/backend/log_events/tests.py b/backend/log_events/tests.py new file mode 100644 index 000000000..7ce503c2d --- /dev/null +++ b/backend/log_events/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/backend/log_events/urls.py b/backend/log_events/urls.py new file mode 100644 index 000000000..f7a409424 --- /dev/null +++ b/backend/log_events/urls.py @@ -0,0 +1,3 @@ +# from . import views + +urlpatterns = [] # type: ignore diff --git a/backend/log_events/views.py b/backend/log_events/views.py new file mode 100644 index 000000000..0bf0473a8 --- /dev/null +++ b/backend/log_events/views.py @@ -0,0 +1,67 @@ +import logging +import threading +from typing import Any + +import redis +import socketio +from django.conf import settings + +logger = logging.getLogger(__name__) + +# Set async_mode to 'threading', 'eventlet', 'gevent' or 'gevent_uwsgi' to +# force a mode else, the best mode is selected automatically from what's +# installed. +# Enable socketio logger if needed +# engineio_logger=True, +sio = socketio.Server( + async_mode="threading", + cors_allowed_origins="*", + logger=False, + engineio_logger=False, + always_connect=True, + ping_timeout=300, # We need to decide and finalize the value +) + +redis_conn = redis.Redis( + host=settings.REDIS_HOST, + port=int(settings.REDIS_PORT), + username=settings.REDIS_USER, + password=settings.REDIS_PASSWORD, +) + + +@sio.event +def connect(sid: str, environ: Any) -> None: + logger.info(f"Client with SID:{sid} connected") + + +@sio.event +def disconnect(sid: str) -> None: + logger.info(f"Client with--------------------Client SID:{sid} disconnected") + + +def handle_pub_sub_messages(message: Any) -> None: + channel = message["channel"].decode("utf-8") + data = message["data"] + sio.emit(channel, {"data": data}) + + +def background_task_for_pub_sub() -> None: + channel_pattern = "logs:*" + try: + # Subscribe to the Redis Pub/Sub channel + pubsub = redis_conn.pubsub(ignore_subscribe_messages=True) + pubsub.psubscribe(channel_pattern) + + # Start listening for messages from Redis + for message in pubsub.listen(): # type: ignore + if message["type"] == "pmessage": + handle_pub_sub_messages(message) + except Exception as e: + logger.error(f"Error occured in background task to pubsub::{e}") + + +background_thread = threading.Thread( + target=background_task_for_pub_sub, daemon=True +) +background_thread.start() diff --git a/backend/manage.py b/backend/manage.py new file mode 100755 index 000000000..c5d2f5890 --- /dev/null +++ b/backend/manage.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +"""Django's command-line utility for administrative tasks.""" +import os +import sys + +from dotenv import load_dotenv + + +def main() -> None: + """Run administrative tasks.""" + load_dotenv() + os.environ.setdefault( + "DJANGO_SETTINGS_MODULE", + os.environ.get("DJANGO_SETTINGS_MODULE", "backend.settings.dev"), + ) + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() diff --git a/backend/middleware/__init__.py b/backend/middleware/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/middleware/exception.py b/backend/middleware/exception.py new file mode 100644 index 000000000..a03ac6872 --- /dev/null +++ b/backend/middleware/exception.py @@ -0,0 +1,85 @@ +import json +import logging +import traceback +from typing import Any, Optional + +from django.conf import settings +from django.http import HttpRequest, HttpResponse +from drf_standardized_errors.handler import exception_handler +from rest_framework.response import Response + +logger = logging.getLogger(__name__) + + +def drf_logging_exc_handler(exc: Exception, context: Any) -> Optional[Response]: + """Custom exception handler for DRF. + + DRF's exception handler takes care of Http404, PermissionDenied and + APIExceptions by default. This function helps log the traceback for + all types of exception and then handles it with DRF or Django + + Args: + exc (Exception): Implementation of Exception raised + context (dict[str, Any]): Dictionary containing additional + metadata on the request itself + + Returns: + Optional[Response]: Returns either a Response if handled, \ + if None it will be + handled by another method in the middleware + """ + request = context.get("request") + ExceptionLoggingMiddleware.format_exc_and_log( + request=request, exception=exc + ) + return exception_handler(exc=exc, context=context) + + +class ExceptionLoggingMiddleware: + """Custom middleware to log unhandled errors. + + DRF middleware handles most exception types, Django takes care of + handling the rest. + """ + + def __init__(self, get_response: Any) -> None: + self.get_response = get_response + + def __call__(self, request: HttpRequest) -> HttpResponse: + response = self.get_response(request) + return response + + def process_exception( + self, request: HttpRequest, exception: Exception + ) -> Optional[HttpResponse]: + """Django hook to handle exceptions by a middleware. + + Args: + request (HttpRequest): Request that was made + exception (Exception): Exception that was raised + + Returns: + Optional[HttpResponse]: Returns either a HttpResponse if handled + If None it will be handled by another method in the middleware + """ + # Handle only when running in production, for debug mode + # Django takes care of displaying a detailed HTML page. + if not settings.DEBUG and exception: + detail = {"detail": "Error processing the request."} + return HttpResponse(json.dumps(detail), status=500) + return None + + @staticmethod + def format_exc_and_log(request: HttpRequest, exception: Exception) -> None: + """Format the exception to be logged and logs it. + + Args: + request (HttpRequest): Request to get API endpoint hit + exception (Exception): Exception that was raised to be logged + """ + message = "**{url}**\n\n{error}\n\n````{tb}````".format( + url=request.build_absolute_uri(), + error=repr(exception), + tb=traceback.format_exc(), + ) + logger.error(message) diff --git a/backend/pdm.lock b/backend/pdm.lock new file mode 100644 index 000000000..371626ea0 --- /dev/null +++ b/backend/pdm.lock @@ -0,0 +1,5004 @@ +# This file is @generated by PDM. +# It is not intended for manual editing. + +[metadata] +groups = ["default", "deploy", "test"] +strategy = ["cross_platform", "inherit_metadata"] +lock_version = "4.4.1" +content_hash = "sha256:9fb9cc53be1e2e98df6da5f2eee39151edd648e25a231d655be7d626b3e25746" + +[[package]] +name = "aiobotocore" +version = "2.5.4" +requires_python = ">=3.7" +summary = "Async client for aws services using botocore and aiohttp" +groups = ["default"] +dependencies = [ + "aiohttp<4.0.0,>=3.3.1", + "aioitertools<1.0.0,>=0.5.1", + "botocore<1.31.18,>=1.31.17", + "wrapt<2.0.0,>=1.10.10", +] +files = [ + {file = "aiobotocore-2.5.4-py3-none-any.whl", hash = "sha256:4b32218728ca3d0be83835b604603a0cd6c329066e884bb78149334267f92440"}, + {file = "aiobotocore-2.5.4.tar.gz", hash = "sha256:60341f19eda77e41e1ab11eef171b5a98b5dbdb90804f5334b6f90e560e31fae"}, +] + +[[package]] +name = "aiobotocore" +version = "2.5.4" +extras = ["boto3"] +requires_python = ">=3.7" +summary = "Async client for aws services using botocore and aiohttp" +groups = ["default"] +dependencies = [ + "aiobotocore==2.5.4", + "boto3<1.28.18,>=1.28.17", +] +files = [ + {file = "aiobotocore-2.5.4-py3-none-any.whl", hash = "sha256:4b32218728ca3d0be83835b604603a0cd6c329066e884bb78149334267f92440"}, + {file = "aiobotocore-2.5.4.tar.gz", hash = "sha256:60341f19eda77e41e1ab11eef171b5a98b5dbdb90804f5334b6f90e560e31fae"}, +] + +[[package]] +name = "aiohttp" +version = "3.9.3" +requires_python = ">=3.8" +summary = "Async http client/server framework (asyncio)" +groups = ["default"] +dependencies = [ + "aiosignal>=1.1.2", + "async-timeout<5.0,>=4.0; python_version < \"3.11\"", + "attrs>=17.3.0", + "frozenlist>=1.1.1", + "multidict<7.0,>=4.5", + "yarl<2.0,>=1.0", +] +files = [ + {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"}, + {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"}, + {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"}, + {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"}, + {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d"}, + {file = "aiohttp-3.9.3-cp39-cp39-win32.whl", hash = "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051"}, + {file = "aiohttp-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc"}, + {file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"}, +] + +[[package]] +name = "aioitertools" +version = "0.11.0" +requires_python = ">=3.6" +summary = "itertools and builtins for AsyncIO and mixed iterables" +groups = ["default"] +dependencies = [ + "typing-extensions>=4.0; python_version < \"3.10\"", +] +files = [ + {file = "aioitertools-0.11.0-py3-none-any.whl", hash = "sha256:04b95e3dab25b449def24d7df809411c10e62aab0cbe31a50ca4e68748c43394"}, + {file = "aioitertools-0.11.0.tar.gz", hash = "sha256:42c68b8dd3a69c2bf7f2233bf7df4bb58b557bca5252ac02ed5187bbc67d6831"}, +] + +[[package]] +name = "aiosignal" +version = "1.3.1" +requires_python = ">=3.7" +summary = "aiosignal: a list of registered asynchronous callbacks" +groups = ["default"] +dependencies = [ + "frozenlist>=1.1.0", +] +files = [ + {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, + {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, +] + +[[package]] +name = "amqp" +version = "5.2.0" +requires_python = ">=3.6" +summary = "Low-level AMQP client for Python (fork of amqplib)." +groups = ["default"] +dependencies = [ + "vine<6.0.0,>=5.0.0", +] +files = [ + {file = "amqp-5.2.0-py3-none-any.whl", hash = "sha256:827cb12fb0baa892aad844fd95258143bce4027fdac4fccddbc43330fd281637"}, + {file = "amqp-5.2.0.tar.gz", hash = "sha256:a1ecff425ad063ad42a486c902807d1482311481c8ad95a72694b2975e75f7fd"}, +] + +[[package]] +name = "annotated-types" +version = "0.6.0" +requires_python = ">=3.8" +summary = "Reusable constraint types to use with typing.Annotated" +groups = ["default"] +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 = "anthropic" +version = "0.7.8" +requires_python = ">=3.7" +summary = "The official Python library for the anthropic API" +groups = ["default"] +dependencies = [ + "anyio<5,>=3.5.0", + "distro<2,>=1.7.0", + "httpx<1,>=0.23.0", + "pydantic<3,>=1.9.0", + "sniffio", + "tokenizers>=0.13.0", + "typing-extensions<5,>=4.5", +] +files = [ + {file = "anthropic-0.7.8-py3-none-any.whl", hash = "sha256:268db974578e34d1449cd0d22389394f0c61795ace9a101dcde4eab4b98439bf"}, + {file = "anthropic-0.7.8.tar.gz", hash = "sha256:61bc698553b24bc7721cf71db8de50703f3025ea2d14fa4bcb5b1d2bf37f9e40"}, +] + +[[package]] +name = "anyio" +version = "4.3.0" +requires_python = ">=3.8" +summary = "High level compatibility layer for multiple asynchronous event loop implementations" +groups = ["default"] +dependencies = [ + "exceptiongroup>=1.0.2; python_version < \"3.11\"", + "idna>=2.8", + "sniffio>=1.1", + "typing-extensions>=4.1; python_version < \"3.11\"", +] +files = [ + {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, + {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, +] + +[[package]] +name = "anyscale" +version = "0.5.165" +summary = "Command Line Interface for Anyscale" +groups = ["default"] +dependencies = [ + "Click>=7.0", + "GitPython", + "aiohttp>=3.7.4.post0", + "argon2-cffi", + "boto3>=1.26.76", + "botocore>=1.19.52", + "certifi>=2023.7.22", + "colorama", + "google-auth", + "halo", + "humanize", + "jsonpatch", + "jsonschema", + "oauth2client", + "packaging", + "pathspec>=0.8.1", + "python-dateutil", + "pyyaml", + "requests", + "rich", + "six>=1.10", + "smart-open", + "tabulate", + "tqdm", + "typing-extensions", + "tzlocal", + "urllib3>=1.26.17", + "wrapt", +] +files = [ + {file = "anyscale-0.5.165.tar.gz", hash = "sha256:a5581567bd191be21c929e9339a9becdd4ba64bc2206b6d087618e9353b15dde"}, +] + +[[package]] +name = "appdirs" +version = "1.4.4" +summary = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +groups = ["default"] +files = [ + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, +] + +[[package]] +name = "argon2-cffi" +version = "23.1.0" +requires_python = ">=3.7" +summary = "Argon2 for Python" +groups = ["default"] +dependencies = [ + "argon2-cffi-bindings", +] +files = [ + {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, + {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, +] + +[[package]] +name = "argon2-cffi-bindings" +version = "21.2.0" +requires_python = ">=3.6" +summary = "Low-level CFFI bindings for Argon2" +groups = ["default"] +dependencies = [ + "cffi>=1.0.1", +] +files = [ + {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, + {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, +] + +[[package]] +name = "asgiref" +version = "3.7.2" +requires_python = ">=3.7" +summary = "ASGI specs, helper code, and adapters" +groups = ["default"] +dependencies = [ + "typing-extensions>=4; python_version < \"3.11\"", +] +files = [ + {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, + {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, +] + +[[package]] +name = "asn1crypto" +version = "1.5.1" +summary = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP" +groups = ["default"] +files = [ + {file = "asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67"}, + {file = "asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c"}, +] + +[[package]] +name = "async-timeout" +version = "4.0.3" +requires_python = ">=3.7" +summary = "Timeout context manager for asyncio programs" +groups = ["default"] +marker = "python_version < \"3.12.0\"" +files = [ + {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, + {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, +] + +[[package]] +name = "asyncpg" +version = "0.29.0" +requires_python = ">=3.8.0" +summary = "An asyncio PostgreSQL driver" +groups = ["default"] +dependencies = [ + "async-timeout>=4.0.3; python_version < \"3.12.0\"", +] +files = [ + {file = "asyncpg-0.29.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72fd0ef9f00aeed37179c62282a3d14262dbbafb74ec0ba16e1b1864d8a12169"}, + {file = "asyncpg-0.29.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52e8f8f9ff6e21f9b39ca9f8e3e33a5fcdceaf5667a8c5c32bee158e313be385"}, + {file = "asyncpg-0.29.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e6823a7012be8b68301342ba33b4740e5a166f6bbda0aee32bc01638491a22"}, + {file = "asyncpg-0.29.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:746e80d83ad5d5464cfbf94315eb6744222ab00aa4e522b704322fb182b83610"}, + {file = "asyncpg-0.29.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ff8e8109cd6a46ff852a5e6bab8b0a047d7ea42fcb7ca5ae6eaae97d8eacf397"}, + {file = "asyncpg-0.29.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:97eb024685b1d7e72b1972863de527c11ff87960837919dac6e34754768098eb"}, + {file = "asyncpg-0.29.0-cp310-cp310-win32.whl", hash = "sha256:5bbb7f2cafd8d1fa3e65431833de2642f4b2124be61a449fa064e1a08d27e449"}, + {file = "asyncpg-0.29.0-cp310-cp310-win_amd64.whl", hash = "sha256:76c3ac6530904838a4b650b2880f8e7af938ee049e769ec2fba7cd66469d7772"}, + {file = "asyncpg-0.29.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4900ee08e85af01adb207519bb4e14b1cae8fd21e0ccf80fac6aa60b6da37b4"}, + {file = "asyncpg-0.29.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a65c1dcd820d5aea7c7d82a3fdcb70e096f8f70d1a8bf93eb458e49bfad036ac"}, + {file = "asyncpg-0.29.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b52e46f165585fd6af4863f268566668407c76b2c72d366bb8b522fa66f1870"}, + {file = "asyncpg-0.29.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc600ee8ef3dd38b8d67421359779f8ccec30b463e7aec7ed481c8346decf99f"}, + {file = "asyncpg-0.29.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:039a261af4f38f949095e1e780bae84a25ffe3e370175193174eb08d3cecab23"}, + {file = "asyncpg-0.29.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6feaf2d8f9138d190e5ec4390c1715c3e87b37715cd69b2c3dfca616134efd2b"}, + {file = "asyncpg-0.29.0-cp311-cp311-win32.whl", hash = "sha256:1e186427c88225ef730555f5fdda6c1812daa884064bfe6bc462fd3a71c4b675"}, + {file = "asyncpg-0.29.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfe73ffae35f518cfd6e4e5f5abb2618ceb5ef02a2365ce64f132601000587d3"}, + {file = "asyncpg-0.29.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5340dd515d7e52f4c11ada32171d87c05570479dc01dc66d03ee3e150fb695da"}, + {file = "asyncpg-0.29.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e17b52c6cf83e170d3d865571ba574577ab8e533e7361a2b8ce6157d02c665d3"}, + {file = "asyncpg-0.29.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f100d23f273555f4b19b74a96840aa27b85e99ba4b1f18d4ebff0734e78dc090"}, + {file = "asyncpg-0.29.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48e7c58b516057126b363cec8ca02b804644fd012ef8e6c7e23386b7d5e6ce83"}, + {file = "asyncpg-0.29.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f9ea3f24eb4c49a615573724d88a48bd1b7821c890c2effe04f05382ed9e8810"}, + {file = "asyncpg-0.29.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8d36c7f14a22ec9e928f15f92a48207546ffe68bc412f3be718eedccdf10dc5c"}, + {file = "asyncpg-0.29.0-cp39-cp39-win32.whl", hash = "sha256:797ab8123ebaed304a1fad4d7576d5376c3a006a4100380fb9d517f0b59c1ab2"}, + {file = "asyncpg-0.29.0-cp39-cp39-win_amd64.whl", hash = "sha256:cce08a178858b426ae1aa8409b5cc171def45d4293626e7aa6510696d46decd8"}, + {file = "asyncpg-0.29.0.tar.gz", hash = "sha256:d1c49e1f44fffafd9a55e1a9b101590859d881d639ea2922516f5d9c512d354e"}, +] + +[[package]] +name = "attrs" +version = "23.2.0" +requires_python = ">=3.7" +summary = "Classes Without Boilerplate" +groups = ["default"] +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[[package]] +name = "authlib" +version = "1.2.1" +summary = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." +groups = ["default"] +dependencies = [ + "cryptography>=3.2", +] +files = [ + {file = "Authlib-1.2.1-py2.py3-none-any.whl", hash = "sha256:c88984ea00149a90e3537c964327da930779afa4564e354edfd98410bea01911"}, + {file = "Authlib-1.2.1.tar.gz", hash = "sha256:421f7c6b468d907ca2d9afede256f068f87e34d23dd221c07d13d4c234726afb"}, +] + +[[package]] +name = "backoff" +version = "2.2.1" +requires_python = ">=3.7,<4.0" +summary = "Function decoration for backoff and retry" +groups = ["default"] +files = [ + {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, + {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, +] + +[[package]] +name = "beautifulsoup4" +version = "4.12.3" +requires_python = ">=3.6.0" +summary = "Screen-scraping library" +groups = ["default"] +dependencies = [ + "soupsieve>1.2", +] +files = [ + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, +] + +[[package]] +name = "bidict" +version = "0.23.1" +requires_python = ">=3.8" +summary = "The bidirectional mapping library for Python." +groups = ["default"] +files = [ + {file = "bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5"}, + {file = "bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71"}, +] + +[[package]] +name = "billiard" +version = "4.2.0" +requires_python = ">=3.7" +summary = "Python multiprocessing fork with improvements and bugfixes" +groups = ["default"] +files = [ + {file = "billiard-4.2.0-py3-none-any.whl", hash = "sha256:07aa978b308f334ff8282bd4a746e681b3513db5c9a514cbdd810cbbdc19714d"}, + {file = "billiard-4.2.0.tar.gz", hash = "sha256:9a3c3184cb275aa17a732f93f65b20c525d3d9f253722d26a82194803ade5a2c"}, +] + +[[package]] +name = "boto3" +version = "1.28.17" +requires_python = ">= 3.7" +summary = "The AWS SDK for Python" +groups = ["default"] +dependencies = [ + "botocore<1.32.0,>=1.31.17", + "jmespath<2.0.0,>=0.7.1", + "s3transfer<0.7.0,>=0.6.0", +] +files = [ + {file = "boto3-1.28.17-py3-none-any.whl", hash = "sha256:bca0526f819e0f19c0f1e6eba3e2d1d6b6a92a45129f98c0d716e5aab6d9444b"}, + {file = "boto3-1.28.17.tar.gz", hash = "sha256:90f7cfb5e1821af95b1fc084bc50e6c47fa3edc99f32de1a2591faa0c546bea7"}, +] + +[[package]] +name = "botocore" +version = "1.31.17" +requires_python = ">= 3.7" +summary = "Low-level, data-driven core of boto 3." +groups = ["default"] +dependencies = [ + "jmespath<2.0.0,>=0.7.1", + "python-dateutil<3.0.0,>=2.1", + "urllib3<1.27,>=1.25.4", +] +files = [ + {file = "botocore-1.31.17-py3-none-any.whl", hash = "sha256:6ac34a1d34aa3750e78b77b8596617e2bab938964694d651939dba2cbde2c12b"}, + {file = "botocore-1.31.17.tar.gz", hash = "sha256:396459065dba4339eb4da4ec8b4e6599728eb89b7caaceea199e26f7d824a41c"}, +] + +[[package]] +name = "boxfs" +version = "0.2.1" +requires_python = ">=3.8,<4.0" +summary = "Implementation of fsspec for Box file storage" +groups = ["default"] +dependencies = [ + "boxsdk[jwt]<4.0,>=3.7", + "fsspec>=2023.4", +] +files = [ + {file = "boxfs-0.2.1-py3-none-any.whl", hash = "sha256:ae796c30309bd5a02654fff9eddf1ed320356225568fad0e109e1942beaef72a"}, + {file = "boxfs-0.2.1.tar.gz", hash = "sha256:c1889e12f53be3216b44f088237ac0f367a7a759a53b01b0c0edf2b3d694e50f"}, +] + +[[package]] +name = "boxsdk" +version = "3.9.2" +summary = "Official Box Python SDK" +groups = ["default"] +dependencies = [ + "attrs>=17.3.0", + "python-dateutil", + "requests-toolbelt>=0.4.0", + "requests<3,>=2.4.3", + "urllib3", +] +files = [ + {file = "boxsdk-3.9.2-py2.py3-none-any.whl", hash = "sha256:44087bc208d3082e0a791f98e491c2eccc61cd5123cedc96e52d089e12c5f410"}, + {file = "boxsdk-3.9.2.tar.gz", hash = "sha256:10e23e2f82e9cff2b2e501b7ca7ffe7bac0e280d1cd4b2983dea95f826e3008b"}, +] + +[[package]] +name = "boxsdk" +version = "3.9.2" +extras = ["jwt"] +summary = "Official Box Python SDK" +groups = ["default"] +dependencies = [ + "boxsdk==3.9.2", + "cryptography>=3", + "pyjwt>=1.7.0", +] +files = [ + {file = "boxsdk-3.9.2-py2.py3-none-any.whl", hash = "sha256:44087bc208d3082e0a791f98e491c2eccc61cd5123cedc96e52d089e12c5f410"}, + {file = "boxsdk-3.9.2.tar.gz", hash = "sha256:10e23e2f82e9cff2b2e501b7ca7ffe7bac0e280d1cd4b2983dea95f826e3008b"}, +] + +[[package]] +name = "cachetools" +version = "5.3.2" +requires_python = ">=3.7" +summary = "Extensible memoizing collections and decorators" +groups = ["default"] +files = [ + {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"}, + {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, +] + +[[package]] +name = "celery" +version = "5.3.6" +requires_python = ">=3.8" +summary = "Distributed Task Queue." +groups = ["default"] +dependencies = [ + "billiard<5.0,>=4.2.0", + "click-didyoumean>=0.3.0", + "click-plugins>=1.1.1", + "click-repl>=0.2.0", + "click<9.0,>=8.1.2", + "kombu<6.0,>=5.3.4", + "python-dateutil>=2.8.2", + "tzdata>=2022.7", + "vine<6.0,>=5.1.0", +] +files = [ + {file = "celery-5.3.6-py3-none-any.whl", hash = "sha256:9da4ea0118d232ce97dff5ed4974587fb1c0ff5c10042eb15278487cdd27d1af"}, + {file = "celery-5.3.6.tar.gz", hash = "sha256:870cc71d737c0200c397290d730344cc991d13a057534353d124c9380267aab9"}, +] + +[[package]] +name = "certifi" +version = "2024.2.2" +requires_python = ">=3.6" +summary = "Python package for providing Mozilla's CA Bundle." +groups = ["default"] +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 = "cffi" +version = "1.16.0" +requires_python = ">=3.8" +summary = "Foreign Function Interface for Python calling C code." +groups = ["default"] +dependencies = [ + "pycparser", +] +files = [ + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +requires_python = ">=3.7.0" +summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +groups = ["default"] +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-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" +requires_python = ">=3.7" +summary = "Composable command line interface toolkit" +groups = ["default"] +dependencies = [ + "colorama; platform_system == \"Windows\"", +] +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[[package]] +name = "click-didyoumean" +version = "0.3.0" +requires_python = ">=3.6.2,<4.0.0" +summary = "Enables git-like *did-you-mean* feature in click" +groups = ["default"] +dependencies = [ + "click>=7", +] +files = [ + {file = "click-didyoumean-0.3.0.tar.gz", hash = "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035"}, + {file = "click_didyoumean-0.3.0-py3-none-any.whl", hash = "sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667"}, +] + +[[package]] +name = "click-plugins" +version = "1.1.1" +summary = "An extension module for click to enable registering CLI commands via setuptools entry-points." +groups = ["default"] +dependencies = [ + "click>=4.0", +] +files = [ + {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, + {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"}, +] + +[[package]] +name = "click-repl" +version = "0.3.0" +requires_python = ">=3.6" +summary = "REPL plugin for Click" +groups = ["default"] +dependencies = [ + "click>=7.0", + "prompt-toolkit>=3.0.36", +] +files = [ + {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"}, + {file = "click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." +groups = ["default", "test"] +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 = "coloredlogs" +version = "15.0.1" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +summary = "Colored terminal output for Python's logging module" +groups = ["default"] +dependencies = [ + "humanfriendly>=9.1", +] +files = [ + {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"}, + {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"}, +] + +[[package]] +name = "cron-descriptor" +version = "1.4.0" +summary = "A Python library that converts cron expressions into human readable strings." +groups = ["default"] +files = [ + {file = "cron_descriptor-1.4.0.tar.gz", hash = "sha256:b6ff4e3a988d7ca04a4ab150248e9f166fb7a5c828a85090e75bcc25aa93b4dd"}, +] + +[[package]] +name = "cryptography" +version = "41.0.7" +requires_python = ">=3.7" +summary = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +groups = ["default"] +dependencies = [ + "cffi>=1.12", +] +files = [ + {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf"}, + {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1"}, + {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157"}, + {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406"}, + {file = "cryptography-41.0.7-cp37-abi3-win32.whl", hash = "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d"}, + {file = "cryptography-41.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309"}, + {file = "cryptography-41.0.7.tar.gz", hash = "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc"}, +] + +[[package]] +name = "dataclasses-json" +version = "0.6.4" +requires_python = ">=3.7,<4.0" +summary = "Easily serialize dataclasses to and from JSON." +groups = ["default"] +dependencies = [ + "marshmallow<4.0.0,>=3.18.0", + "typing-inspect<1,>=0.4.0", +] +files = [ + {file = "dataclasses_json-0.6.4-py3-none-any.whl", hash = "sha256:f90578b8a3177f7552f4e1a6e535e84293cd5da421fcce0642d49c0d7bdf8df2"}, + {file = "dataclasses_json-0.6.4.tar.gz", hash = "sha256:73696ebf24936560cca79a2430cbc4f3dd23ac7bf46ed17f38e5e5e7657a6377"}, +] + +[[package]] +name = "defusedxml" +version = "0.8.0rc2" +requires_python = ">=3.6" +summary = "XML bomb protection for Python stdlib modules" +groups = ["default"] +files = [ + {file = "defusedxml-0.8.0rc2-py2.py3-none-any.whl", hash = "sha256:1c812964311154c3bf4aaf3bc1443b31ee13530b7f255eaaa062c0553c76103d"}, + {file = "defusedxml-0.8.0rc2.tar.gz", hash = "sha256:138c7d540a78775182206c7c97fe65b246a2f40b29471e1a2f1b0da76e7a3942"}, +] + +[[package]] +name = "deprecated" +version = "1.2.14" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +summary = "Python @deprecated decorator to deprecate old python classes, functions or methods." +groups = ["default"] +dependencies = [ + "wrapt<2,>=1.10", +] +files = [ + {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"}, + {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"}, +] + +[[package]] +name = "deprecation" +version = "2.1.0" +summary = "A library to handle automated deprecations" +groups = ["default"] +dependencies = [ + "packaging", +] +files = [ + {file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a"}, + {file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff"}, +] + +[[package]] +name = "distro" +version = "1.9.0" +requires_python = ">=3.6" +summary = "Distro - an OS platform information API" +groups = ["default"] +files = [ + {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, + {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, +] + +[[package]] +name = "django" +version = "4.2.1" +requires_python = ">=3.8" +summary = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +groups = ["default"] +dependencies = [ + "asgiref<4,>=3.6.0", + "sqlparse>=0.3.1", + "tzdata; sys_platform == \"win32\"", +] +files = [ + {file = "Django-4.2.1-py3-none-any.whl", hash = "sha256:066b6debb5ac335458d2a713ed995570536c8b59a580005acb0732378d5eb1ee"}, + {file = "Django-4.2.1.tar.gz", hash = "sha256:7efa6b1f781a6119a10ac94b4794ded90db8accbe7802281cd26f8664ffed59c"}, +] + +[[package]] +name = "django-celery-beat" +version = "2.5.0" +summary = "Database-backed Periodic Tasks." +groups = ["default"] +dependencies = [ + "Django<5.0,>=2.2", + "celery<6.0,>=5.2.3", + "cron-descriptor>=1.2.32", + "django-timezone-field>=5.0", + "python-crontab>=2.3.4", + "tzdata", +] +files = [ + {file = "django-celery-beat-2.5.0.tar.gz", hash = "sha256:cd0a47f5958402f51ac0c715bc942ae33d7b50b4e48cba91bc3f2712be505df1"}, + {file = "django_celery_beat-2.5.0-py3-none-any.whl", hash = "sha256:ae460faa5ea142fba0875409095d22f6bd7bcc7377889b85e8cab5c0dfb781fe"}, +] + +[[package]] +name = "django-cors-headers" +version = "4.3.1" +requires_python = ">=3.8" +summary = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)." +groups = ["default"] +dependencies = [ + "Django>=3.2", + "asgiref>=3.6", +] +files = [ + {file = "django-cors-headers-4.3.1.tar.gz", hash = "sha256:0bf65ef45e606aff1994d35503e6b677c0b26cafff6506f8fd7187f3be840207"}, + {file = "django_cors_headers-4.3.1-py3-none-any.whl", hash = "sha256:0b1fd19297e37417fc9f835d39e45c8c642938ddba1acce0c1753d3edef04f36"}, +] + +[[package]] +name = "django-redis" +version = "5.4.0" +requires_python = ">=3.6" +summary = "Full featured redis cache backend for Django." +groups = ["default"] +dependencies = [ + "Django>=3.2", + "redis!=4.0.0,!=4.0.1,>=3", +] +files = [ + {file = "django-redis-5.4.0.tar.gz", hash = "sha256:6a02abaa34b0fea8bf9b707d2c363ab6adc7409950b2db93602e6cb292818c42"}, + {file = "django_redis-5.4.0-py3-none-any.whl", hash = "sha256:ebc88df7da810732e2af9987f7f426c96204bf89319df4c6da6ca9a2942edd5b"}, +] + +[[package]] +name = "django-tenants" +version = "3.5.0" +summary = "Tenant support for Django using PostgreSQL schemas." +groups = ["default"] +dependencies = [ + "Django<4.3,>=2.1", +] +files = [ + {file = "django-tenants-3.5.0.tar.gz", hash = "sha256:bed426108e1bd4f962afa38c1e0fd985a3e8c4c902ded60bd57dbf4fcc92d2cc"}, +] + +[[package]] +name = "django-timezone-field" +version = "6.1.0" +requires_python = ">=3.8,<4.0" +summary = "A Django app providing DB, form, and REST framework fields for zoneinfo and pytz timezone objects." +groups = ["default"] +dependencies = [ + "Django<6.0,>=3.2", +] +files = [ + {file = "django_timezone_field-6.1.0-py3-none-any.whl", hash = "sha256:0095f43da716552fcc606783cfb42cb025892514f1ec660ebfa96186eb83b74c"}, + {file = "django_timezone_field-6.1.0.tar.gz", hash = "sha256:d40f7059d7bae4075725d04a9dae601af9fe3c7f0119a69b0e2c6194a782f797"}, +] + +[[package]] +name = "djangorestframework" +version = "3.14.0" +requires_python = ">=3.6" +summary = "Web APIs for Django, made easy." +groups = ["default"] +dependencies = [ + "django>=3.0", + "pytz", +] +files = [ + {file = "djangorestframework-3.14.0-py3-none-any.whl", hash = "sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08"}, + {file = "djangorestframework-3.14.0.tar.gz", hash = "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8"}, +] + +[[package]] +name = "dnspython" +version = "2.6.1" +requires_python = ">=3.8" +summary = "DNS toolkit" +groups = ["default"] +files = [ + {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, + {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, +] + +[[package]] +name = "docker" +version = "6.1.3" +requires_python = ">=3.7" +summary = "A Python library for the Docker Engine API." +groups = ["default"] +dependencies = [ + "packaging>=14.0", + "pywin32>=304; sys_platform == \"win32\"", + "requests>=2.26.0", + "urllib3>=1.26.0", + "websocket-client>=0.32.0", +] +files = [ + {file = "docker-6.1.3-py3-none-any.whl", hash = "sha256:aecd2277b8bf8e506e484f6ab7aec39abe0038e29fa4a6d3ba86c3fe01844ed9"}, + {file = "docker-6.1.3.tar.gz", hash = "sha256:aa6d17830045ba5ef0168d5eaa34d37beeb113948c413affe1d5991fc11f9a20"}, +] + +[[package]] +name = "drf-standardized-errors" +version = "0.12.6" +requires_python = ">=3.8" +summary = "Standardize your API error responses." +groups = ["default"] +dependencies = [ + "django>=3.2", + "djangorestframework>=3.12", +] +files = [ + {file = "drf_standardized_errors-0.12.6-py3-none-any.whl", hash = "sha256:6f71d895427a5c4658c7c653ebd3755840514e0cc6a433e484808ad5191b22ee"}, + {file = "drf_standardized_errors-0.12.6.tar.gz", hash = "sha256:f71d5fce12bca8d1ce41cc65024014efbddb35c6b51a193db9a938b57385100d"}, +] + +[[package]] +name = "drf-yasg" +version = "1.21.7" +requires_python = ">=3.6" +summary = "Automated generation of real Swagger/OpenAPI 2.0 schemas from Django Rest Framework code." +groups = ["default"] +dependencies = [ + "django>=2.2.16", + "djangorestframework>=3.10.3", + "inflection>=0.3.1", + "packaging>=21.0", + "pytz>=2021.1", + "pyyaml>=5.1", + "uritemplate>=3.0.0", +] +files = [ + {file = "drf-yasg-1.21.7.tar.gz", hash = "sha256:4c3b93068b3dfca6969ab111155e4dd6f7b2d680b98778de8fd460b7837bdb0d"}, + {file = "drf_yasg-1.21.7-py3-none-any.whl", hash = "sha256:f85642072c35e684356475781b7ecf5d218fff2c6185c040664dd49f0a4be181"}, +] + +[[package]] +name = "dropbox" +version = "11.36.2" +summary = "Official Dropbox API Client" +groups = ["default"] +dependencies = [ + "requests>=2.16.2", + "six>=1.12.0", + "stone>=2", +] +files = [ + {file = "dropbox-11.36.2-py3-none-any.whl", hash = "sha256:a21e4d2bcbeb1d8067ff87969aea48792c9a8266182491153feff2be9c1b9c8f"}, + {file = "dropbox-11.36.2.tar.gz", hash = "sha256:d48d3d16d486c78b11c14a1c4a28a2611fbf5a0d0a358b861bfd9482e603c500"}, +] + +[[package]] +name = "dropboxdrivefs" +version = "1.3.1" +requires_python = ">=3.5" +summary = "Dropbox implementation for fsspec module" +groups = ["default"] +dependencies = [ + "dropbox", + "fsspec", + "requests", +] +files = [ + {file = "dropboxdrivefs-1.3.1.tar.gz", hash = "sha256:892ee9017c59648736d79c3989cadb9e129b469fcec0c68d12e42bd6826a962d"}, +] + +[[package]] +name = "environs" +version = "9.5.0" +requires_python = ">=3.6" +summary = "simplified environment variable parsing" +groups = ["default"] +dependencies = [ + "marshmallow>=3.0.0", + "python-dotenv", +] +files = [ + {file = "environs-9.5.0-py2.py3-none-any.whl", hash = "sha256:1e549569a3de49c05f856f40bce86979e7d5ffbbc4398e7f338574c220189124"}, + {file = "environs-9.5.0.tar.gz", hash = "sha256:a76307b36fbe856bdca7ee9161e6c466fd7fcffc297109a118c59b54e27e30c9"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.0" +requires_python = ">=3.7" +summary = "Backport of PEP 654 (exception groups)" +groups = ["default", "test"] +marker = "python_version < \"3.11\"" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[[package]] +name = "fastembed" +version = "0.1.3" +requires_python = ">=3.8.0,<3.12" +summary = "Fast, light, accurate library built for retrieval embedding generation" +groups = ["default"] +dependencies = [ + "huggingface-hub==0.19.4", + "onnx<2.0,>=1.11", + "onnxruntime<2.0,>=1.15", + "requests<3.0,>=2.31", + "tokenizers<0.16.0,>=0.15.0", + "tqdm<5.0,>=4.65", +] +files = [ + {file = "fastembed-0.1.3-py3-none-any.whl", hash = "sha256:98b6c6d9effec8c96d97048e59cdd53627b16a70fcdbfa7c663772de66e11b3a"}, + {file = "fastembed-0.1.3.tar.gz", hash = "sha256:c17dc83a02938f8baae6717f18d24ed0ff0c5397b5329cbb5c7264239411346f"}, +] + +[[package]] +name = "filelock" +version = "3.13.1" +requires_python = ">=3.8" +summary = "A platform independent file lock." +groups = ["default"] +files = [ + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, +] + +[[package]] +name = "filetype" +version = "1.2.0" +summary = "Infer file type and MIME type of any file/buffer. No external dependencies." +groups = ["default"] +files = [ + {file = "filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25"}, + {file = "filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb"}, +] + +[[package]] +name = "flatbuffers" +version = "23.5.26" +summary = "The FlatBuffers serialization format for Python" +groups = ["default"] +files = [ + {file = "flatbuffers-23.5.26-py2.py3-none-any.whl", hash = "sha256:c0ff356da363087b915fde4b8b45bdda73432fc17cddb3c8157472eab1422ad1"}, + {file = "flatbuffers-23.5.26.tar.gz", hash = "sha256:9ea1144cac05ce5d86e2859f431c6cd5e66cd9c78c558317c7955fb8d4c78d89"}, +] + +[[package]] +name = "flower" +version = "2.0.1" +requires_python = ">=3.7" +summary = "Celery Flower" +groups = ["default"] +dependencies = [ + "celery>=5.0.5", + "humanize", + "prometheus-client>=0.8.0", + "pytz", + "tornado<7.0.0,>=5.0.0", +] +files = [ + {file = "flower-2.0.1-py2.py3-none-any.whl", hash = "sha256:9db2c621eeefbc844c8dd88be64aef61e84e2deb29b271e02ab2b5b9f01068e2"}, + {file = "flower-2.0.1.tar.gz", hash = "sha256:5ab717b979530770c16afb48b50d2a98d23c3e9fe39851dcf6bc4d01845a02a0"}, +] + +[[package]] +name = "flupy" +version = "1.2.0" +summary = "Method chaining built on generators" +groups = ["default"] +dependencies = [ + "typing-extensions", +] +files = [ + {file = "flupy-1.2.0.tar.gz", hash = "sha256:12487a008e9744cd35d0f6ea3cfa06f4b2b27cb138bf57d0788f5c26e57afe69"}, +] + +[[package]] +name = "frozenlist" +version = "1.4.1" +requires_python = ">=3.8" +summary = "A list-like structure which implements collections.abc.MutableSequence" +groups = ["default"] +files = [ + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, + {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, + {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, + {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, + {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, + {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, + {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, + {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, + {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, +] + +[[package]] +name = "fsspec" +version = "2023.6.0" +requires_python = ">=3.8" +summary = "File-system specification" +groups = ["default"] +files = [ + {file = "fsspec-2023.6.0-py3-none-any.whl", hash = "sha256:1cbad1faef3e391fba6dc005ae9b5bdcbf43005c9167ce78c915549c352c869a"}, + {file = "fsspec-2023.6.0.tar.gz", hash = "sha256:d0b2f935446169753e7a5c5c55681c54ea91996cc67be93c39a154fb3a2742af"}, +] + +[[package]] +name = "funcy" +version = "2.0" +summary = "A fancy and practical functional tools" +groups = ["default"] +files = [ + {file = "funcy-2.0-py2.py3-none-any.whl", hash = "sha256:53df23c8bb1651b12f095df764bfb057935d49537a56de211b098f4c79614bb0"}, + {file = "funcy-2.0.tar.gz", hash = "sha256:3963315d59d41c6f30c04bc910e10ab50a3ac4a225868bfa96feed133df075cb"}, +] + +[[package]] +name = "gitdb" +version = "4.0.11" +requires_python = ">=3.7" +summary = "Git Object Database" +groups = ["default"] +dependencies = [ + "smmap<6,>=3.0.1", +] +files = [ + {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, + {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, +] + +[[package]] +name = "gitpython" +version = "3.1.42" +requires_python = ">=3.7" +summary = "GitPython is a Python library used to interact with Git repositories" +groups = ["default"] +dependencies = [ + "gitdb<5,>=4.0.1", +] +files = [ + {file = "GitPython-3.1.42-py3-none-any.whl", hash = "sha256:1bf9cd7c9e7255f77778ea54359e54ac22a72a5b51288c457c881057b7bb9ecd"}, + {file = "GitPython-3.1.42.tar.gz", hash = "sha256:2d99869e0fef71a73cbd242528105af1d6c1b108c60dfabd994bf292f76c3ceb"}, +] + +[[package]] +name = "google-ai-generativelanguage" +version = "0.4.0" +requires_python = ">=3.7" +summary = "Google Ai Generativelanguage API client library" +groups = ["default"] +dependencies = [ + "google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.0", + "proto-plus<2.0.0dev,>=1.22.3", + "protobuf!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev,>=3.19.5", +] +files = [ + {file = "google-ai-generativelanguage-0.4.0.tar.gz", hash = "sha256:c8199066c08f74c4e91290778329bb9f357ba1ea5d6f82de2bc0d10552bf4f8c"}, + {file = "google_ai_generativelanguage-0.4.0-py3-none-any.whl", hash = "sha256:e4c425376c1ee26c78acbc49a24f735f90ebfa81bf1a06495fae509a2433232c"}, +] + +[[package]] +name = "google-api-core" +version = "2.17.1" +requires_python = ">=3.7" +summary = "Google API client core library" +groups = ["default"] +dependencies = [ + "google-auth<3.0.dev0,>=2.14.1", + "googleapis-common-protos<2.0.dev0,>=1.56.2", + "protobuf!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0.dev0,>=3.19.5", + "requests<3.0.0.dev0,>=2.18.0", +] +files = [ + {file = "google-api-core-2.17.1.tar.gz", hash = "sha256:9df18a1f87ee0df0bc4eea2770ebc4228392d8cc4066655b320e2cfccb15db95"}, + {file = "google_api_core-2.17.1-py3-none-any.whl", hash = "sha256:610c5b90092c360736baccf17bd3efbcb30dd380e7a6dc28a71059edb8bd0d8e"}, +] + +[[package]] +name = "google-api-core" +version = "2.17.1" +extras = ["grpc"] +requires_python = ">=3.7" +summary = "Google API client core library" +groups = ["default"] +dependencies = [ + "google-api-core==2.17.1", + "grpcio-status<2.0.dev0,>=1.33.2", + "grpcio-status<2.0.dev0,>=1.49.1; python_version >= \"3.11\"", + "grpcio<2.0dev,>=1.33.2", + "grpcio<2.0dev,>=1.49.1; python_version >= \"3.11\"", +] +files = [ + {file = "google-api-core-2.17.1.tar.gz", hash = "sha256:9df18a1f87ee0df0bc4eea2770ebc4228392d8cc4066655b320e2cfccb15db95"}, + {file = "google_api_core-2.17.1-py3-none-any.whl", hash = "sha256:610c5b90092c360736baccf17bd3efbcb30dd380e7a6dc28a71059edb8bd0d8e"}, +] + +[[package]] +name = "google-api-python-client" +version = "2.119.0" +requires_python = ">=3.7" +summary = "Google API Client Library for Python" +groups = ["default"] +dependencies = [ + "google-api-core!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0.dev0,>=1.31.5", + "google-auth-httplib2>=0.1.0", + "google-auth<3.0.0.dev0,>=1.19.0", + "httplib2<1.dev0,>=0.15.0", + "uritemplate<5,>=3.0.1", +] +files = [ + {file = "google-api-python-client-2.119.0.tar.gz", hash = "sha256:ff9ef7539eaf7e088a481b25d1af4704210b07863e1d51b5ee498b910a3a46a3"}, + {file = "google_api_python_client-2.119.0-py2.py3-none-any.whl", hash = "sha256:84e43bdb58dd8d2301669513863996378ffe9a3bf6d23b5ccd4f1e021323dbeb"}, +] + +[[package]] +name = "google-auth" +version = "2.20.0" +requires_python = ">=3.6" +summary = "Google Authentication Library" +groups = ["default"] +dependencies = [ + "cachetools<6.0,>=2.0.0", + "pyasn1-modules>=0.2.1", + "rsa<5,>=3.1.4", + "six>=1.9.0", + "urllib3<2.0", +] +files = [ + {file = "google-auth-2.20.0.tar.gz", hash = "sha256:030af34138909ccde0fbce611afc178f1d65d32fbff281f25738b1fe1c6f3eaa"}, + {file = "google_auth-2.20.0-py2.py3-none-any.whl", hash = "sha256:23b7b0950fcda519bfb6692bf0d5289d2ea49fc143717cc7188458ec620e63fa"}, +] + +[[package]] +name = "google-auth-httplib2" +version = "0.2.0" +summary = "Google Authentication Library: httplib2 transport" +groups = ["default"] +dependencies = [ + "google-auth", + "httplib2>=0.19.0", +] +files = [ + {file = "google-auth-httplib2-0.2.0.tar.gz", hash = "sha256:38aa7badf48f974f1eb9861794e9c0cb2a0511a4ec0679b1f886d108f5640e05"}, + {file = "google_auth_httplib2-0.2.0-py2.py3-none-any.whl", hash = "sha256:b65a0a2123300dd71281a7bf6e64d65a0759287df52729bdd1ae2e47dc311a3d"}, +] + +[[package]] +name = "google-cloud-aiplatform" +version = "1.40.0" +requires_python = ">=3.8" +summary = "Vertex AI API client library" +groups = ["default"] +dependencies = [ + "google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,<3.0.0dev,>=1.32.0", + "google-cloud-bigquery<4.0.0dev,>=1.15.0", + "google-cloud-resource-manager<3.0.0dev,>=1.3.3", + "google-cloud-storage<3.0.0dev,>=1.32.0", + "packaging>=14.3", + "proto-plus<2.0.0dev,>=1.22.0", + "protobuf!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev,>=3.19.5", + "shapely<3.0.0dev", +] +files = [ + {file = "google-cloud-aiplatform-1.40.0.tar.gz", hash = "sha256:1ee9aff2fa27c6852558a2abeaf0ffe0537bff90c5dc9f0e967762ac17291001"}, + {file = "google_cloud_aiplatform-1.40.0-py2.py3-none-any.whl", hash = "sha256:9c67a2664e138387ea82d70dec4b54e081b7de6e1089ed23fdaf66900d00320a"}, +] + +[[package]] +name = "google-cloud-bigquery" +version = "3.11.4" +requires_python = ">=3.7" +summary = "Google BigQuery API client library" +groups = ["default"] +dependencies = [ + "google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5", + "google-cloud-core<3.0.0dev,>=1.6.0", + "google-resumable-media<3.0dev,>=0.6.0", + "grpcio<2.0dev,>=1.47.0", + "grpcio<2.0dev,>=1.49.1; python_version >= \"3.11\"", + "packaging>=20.0.0", + "proto-plus<2.0.0dev,>=1.15.0", + "protobuf!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev,>=3.19.5", + "python-dateutil<3.0dev,>=2.7.2", + "requests<3.0.0dev,>=2.21.0", +] +files = [ + {file = "google-cloud-bigquery-3.11.4.tar.gz", hash = "sha256:697df117241a2283bcbb93b21e10badc14e51c9a90800d2a7e1a3e1c7d842974"}, + {file = "google_cloud_bigquery-3.11.4-py2.py3-none-any.whl", hash = "sha256:5fa7897743a0ed949ade25a0942fc9e7557d8fce307c6f8a76d1b604cf27f1b1"}, +] + +[[package]] +name = "google-cloud-core" +version = "2.4.1" +requires_python = ">=3.7" +summary = "Google Cloud API client core library" +groups = ["default"] +dependencies = [ + "google-api-core!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.6", + "google-auth<3.0dev,>=1.25.0", +] +files = [ + {file = "google-cloud-core-2.4.1.tar.gz", hash = "sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073"}, + {file = "google_cloud_core-2.4.1-py2.py3-none-any.whl", hash = "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61"}, +] + +[[package]] +name = "google-cloud-resource-manager" +version = "1.12.2" +requires_python = ">=3.7" +summary = "Google Cloud Resource Manager API client library" +groups = ["default"] +dependencies = [ + "google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1", + "google-auth<3.0.0dev,>=2.14.1", + "grpc-google-iam-v1<1.0.0dev,>=0.12.4", + "proto-plus<2.0.0dev,>=1.22.3", + "protobuf!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev,>=3.19.5", +] +files = [ + {file = "google-cloud-resource-manager-1.12.2.tar.gz", hash = "sha256:2ede446a5087b236f0e1fb39cca3791bae97eb0d9125057401454b190d5572ee"}, + {file = "google_cloud_resource_manager-1.12.2-py2.py3-none-any.whl", hash = "sha256:45abbb8911195cc831cc77c8e3be84decc271686579b332d4142af507f423ebf"}, +] + +[[package]] +name = "google-cloud-secret-manager" +version = "2.16.1" +requires_python = ">=3.7" +summary = "Google Cloud Secret Manager API client library" +groups = ["default"] +dependencies = [ + "google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.0", + "grpc-google-iam-v1<1.0.0dev,>=0.12.4", + "proto-plus<2.0.0dev,>=1.22.0", + "proto-plus<2.0.0dev,>=1.22.2; python_version >= \"3.11\"", + "protobuf!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev,>=3.19.5", +] +files = [ + {file = "google-cloud-secret-manager-2.16.1.tar.gz", hash = "sha256:149d11ce9be7ea81d4ac3544d3fcd4c716a9edb2cb775d9c075231570b079fbb"}, + {file = "google_cloud_secret_manager-2.16.1-py2.py3-none-any.whl", hash = "sha256:dad28c24921fb62961aafe808be0e7935a99096f03ac29eeeefa04b85534c1f3"}, +] + +[[package]] +name = "google-cloud-storage" +version = "2.9.0" +requires_python = ">=3.7" +summary = "Google Cloud Storage API client library" +groups = ["default"] +dependencies = [ + "google-api-core!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5", + "google-auth<3.0dev,>=1.25.0", + "google-cloud-core<3.0dev,>=2.3.0", + "google-resumable-media>=2.3.2", + "requests<3.0.0dev,>=2.18.0", +] +files = [ + {file = "google-cloud-storage-2.9.0.tar.gz", hash = "sha256:9b6ae7b509fc294bdacb84d0f3ea8e20e2c54a8b4bbe39c5707635fec214eff3"}, + {file = "google_cloud_storage-2.9.0-py2.py3-none-any.whl", hash = "sha256:83a90447f23d5edd045e0037982c270302e3aeb45fc1288d2c2ca713d27bad94"}, +] + +[[package]] +name = "google-crc32c" +version = "1.5.0" +requires_python = ">=3.7" +summary = "A python wrapper of the C library 'Google CRC32C'" +groups = ["default"] +files = [ + {file = "google-crc32c-1.5.0.tar.gz", hash = "sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7"}, + {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13"}, + {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346"}, + {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65"}, + {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b"}, + {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02"}, + {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4"}, + {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e"}, + {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c"}, + {file = "google_crc32c-1.5.0-cp310-cp310-win32.whl", hash = "sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee"}, + {file = "google_crc32c-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289"}, + {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273"}, + {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298"}, + {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57"}, + {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8485b340a6a9e76c62a7dce3c98e5f102c9219f4cfbf896a00cf48caf078d438"}, + {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77e2fd3057c9d78e225fa0a2160f96b64a824de17840351b26825b0848022906"}, + {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f583edb943cf2e09c60441b910d6a20b4d9d626c75a36c8fcac01a6c96c01183"}, + {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a1fd716e7a01f8e717490fbe2e431d2905ab8aa598b9b12f8d10abebb36b04dd"}, + {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c"}, + {file = "google_crc32c-1.5.0-cp311-cp311-win32.whl", hash = "sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709"}, + {file = "google_crc32c-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968"}, + {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7"}, + {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d"}, + {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100"}, + {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9"}, + {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57"}, + {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210"}, + {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd"}, + {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96"}, + {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61"}, + {file = "google_crc32c-1.5.0-cp39-cp39-win32.whl", hash = "sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c"}, + {file = "google_crc32c-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541"}, + {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325"}, + {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd"}, + {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091"}, + {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178"}, + {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2"}, + {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d"}, + {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2"}, + {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5"}, + {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462"}, + {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314"}, + {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728"}, + {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88"}, + {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb"}, + {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31"}, + {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93"}, +] + +[[package]] +name = "google-generativeai" +version = "0.3.1" +requires_python = ">=3.9" +summary = "Google Generative AI High level API client library and tools." +groups = ["default"] +dependencies = [ + "google-ai-generativelanguage==0.4.0", + "google-api-core", + "google-auth", + "protobuf", + "tqdm", +] +files = [ + {file = "google_generativeai-0.3.1-py3-none-any.whl", hash = "sha256:800ec6041ca537b897d7ba654f4125651c64b38506f2bfce3b464370e3333a1b"}, +] + +[[package]] +name = "google-resumable-media" +version = "2.7.0" +requires_python = ">= 3.7" +summary = "Utilities for Google Media Downloads and Resumable Uploads" +groups = ["default"] +dependencies = [ + "google-crc32c<2.0dev,>=1.0", +] +files = [ + {file = "google-resumable-media-2.7.0.tar.gz", hash = "sha256:5f18f5fa9836f4b083162064a1c2c98c17239bfda9ca50ad970ccf905f3e625b"}, + {file = "google_resumable_media-2.7.0-py2.py3-none-any.whl", hash = "sha256:79543cfe433b63fd81c0844b7803aba1bb8950b47bedf7d980c38fa123937e08"}, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.62.0" +requires_python = ">=3.7" +summary = "Common protobufs used in Google APIs" +groups = ["default"] +dependencies = [ + "protobuf!=3.20.0,!=3.20.1,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0.dev0,>=3.19.5", +] +files = [ + {file = "googleapis-common-protos-1.62.0.tar.gz", hash = "sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277"}, + {file = "googleapis_common_protos-1.62.0-py2.py3-none-any.whl", hash = "sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07"}, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.62.0" +extras = ["grpc"] +requires_python = ">=3.7" +summary = "Common protobufs used in Google APIs" +groups = ["default"] +dependencies = [ + "googleapis-common-protos==1.62.0", + "grpcio<2.0.0.dev0,>=1.44.0", +] +files = [ + {file = "googleapis-common-protos-1.62.0.tar.gz", hash = "sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277"}, + {file = "googleapis_common_protos-1.62.0-py2.py3-none-any.whl", hash = "sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07"}, +] + +[[package]] +name = "gotrue" +version = "2.1.0" +requires_python = ">=3.8,<4.0" +summary = "Python Client Library for GoTrue" +groups = ["default"] +dependencies = [ + "httpx<0.26,>=0.23", + "pydantic<3,>=1.10", +] +files = [ + {file = "gotrue-2.1.0-py3-none-any.whl", hash = "sha256:6483d9a3ac9be1d1ad510be24171e133aa1cec702cc10a8f323b9e7519642447"}, + {file = "gotrue-2.1.0.tar.gz", hash = "sha256:b21d48ee64f0f6a1ed111efe4871a83e542529f1a75a264833b50e6433cd3c98"}, +] + +[[package]] +name = "greenlet" +version = "3.0.3" +requires_python = ">=3.7" +summary = "Lightweight in-process concurrent programming" +groups = ["default"] +files = [ + {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, + {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, + {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, + {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, + {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, + {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, + {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, + {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, +] + +[[package]] +name = "grpc-google-iam-v1" +version = "0.13.0" +requires_python = ">=3.7" +summary = "IAM API client library" +groups = ["default"] +dependencies = [ + "googleapis-common-protos[grpc]<2.0.0dev,>=1.56.0", + "grpcio<2.0.0dev,>=1.44.0", + "protobuf!=3.20.0,!=3.20.1,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev,>=3.19.5", +] +files = [ + {file = "grpc-google-iam-v1-0.13.0.tar.gz", hash = "sha256:fad318608b9e093258fbf12529180f400d1c44453698a33509cc6ecf005b294e"}, + {file = "grpc_google_iam_v1-0.13.0-py2.py3-none-any.whl", hash = "sha256:53902e2af7de8df8c1bd91373d9be55b0743ec267a7428ea638db3775becae89"}, +] + +[[package]] +name = "grpcio" +version = "1.58.0" +requires_python = ">=3.7" +summary = "HTTP/2-based RPC framework" +groups = ["default"] +files = [ + {file = "grpcio-1.58.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:3e6bebf1dfdbeb22afd95650e4f019219fef3ab86d3fca8ebade52e4bc39389a"}, + {file = "grpcio-1.58.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:cde11577d5b6fd73a00e6bfa3cf5f428f3f33c2d2878982369b5372bbc4acc60"}, + {file = "grpcio-1.58.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:a2d67ff99e70e86b2be46c1017ae40b4840d09467d5455b2708de6d4c127e143"}, + {file = "grpcio-1.58.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ed979b273a81de36fc9c6716d9fb09dd3443efa18dcc8652501df11da9583e9"}, + {file = "grpcio-1.58.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:458899d2ebd55d5ca2350fd3826dfd8fcb11fe0f79828ae75e2b1e6051d50a29"}, + {file = "grpcio-1.58.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bc7ffef430b80345729ff0a6825e9d96ac87efe39216e87ac58c6c4ef400de93"}, + {file = "grpcio-1.58.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5b23d75e5173faa3d1296a7bedffb25afd2fddb607ef292dfc651490c7b53c3d"}, + {file = "grpcio-1.58.0-cp310-cp310-win32.whl", hash = "sha256:fad9295fe02455d4f158ad72c90ef8b4bcaadfdb5efb5795f7ab0786ad67dd58"}, + {file = "grpcio-1.58.0-cp310-cp310-win_amd64.whl", hash = "sha256:bc325fed4d074367bebd465a20763586e5e1ed5b943e9d8bc7c162b1f44fd602"}, + {file = "grpcio-1.58.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:652978551af02373a5a313e07bfef368f406b5929cf2d50fa7e4027f913dbdb4"}, + {file = "grpcio-1.58.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:9f13a171281ebb4d7b1ba9f06574bce2455dcd3f2f6d1fbe0fd0d84615c74045"}, + {file = "grpcio-1.58.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:8774219e21b05f750eef8adc416e9431cf31b98f6ce9def288e4cea1548cbd22"}, + {file = "grpcio-1.58.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09206106848462763f7f273ca93d2d2d4d26cab475089e0de830bb76be04e9e8"}, + {file = "grpcio-1.58.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62831d5e251dd7561d9d9e83a0b8655084b2a1f8ea91e4bd6b3cedfefd32c9d2"}, + {file = "grpcio-1.58.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:212f38c6a156862098f6bdc9a79bf850760a751d259d8f8f249fc6d645105855"}, + {file = "grpcio-1.58.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4b12754af201bb993e6e2efd7812085ddaaef21d0a6f0ff128b97de1ef55aa4a"}, + {file = "grpcio-1.58.0-cp311-cp311-win32.whl", hash = "sha256:3886b4d56bd4afeac518dbc05933926198aa967a7d1d237a318e6fbc47141577"}, + {file = "grpcio-1.58.0-cp311-cp311-win_amd64.whl", hash = "sha256:002f228d197fea12797a14e152447044e14fb4fdb2eb5d6cfa496f29ddbf79ef"}, + {file = "grpcio-1.58.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fe643af248442221db027da43ed43e53b73e11f40c9043738de9a2b4b6ca7697"}, + {file = "grpcio-1.58.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:128eb1f8e70676d05b1b0c8e6600320fc222b3f8c985a92224248b1367122188"}, + {file = "grpcio-1.58.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:039003a5e0ae7d41c86c768ef8b3ee2c558aa0a23cf04bf3c23567f37befa092"}, + {file = "grpcio-1.58.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f061722cad3f9aabb3fbb27f3484ec9d4667b7328d1a7800c3c691a98f16bb0"}, + {file = "grpcio-1.58.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba0af11938acf8cd4cf815c46156bcde36fa5850518120920d52620cc3ec1830"}, + {file = "grpcio-1.58.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d4cef77ad2fed42b1ba9143465856d7e737279854e444925d5ba45fc1f3ba727"}, + {file = "grpcio-1.58.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24765a627eb4d9288ace32d5104161c3654128fe27f2808ecd6e9b0cfa7fc8b9"}, + {file = "grpcio-1.58.0-cp39-cp39-win32.whl", hash = "sha256:f0241f7eb0d2303a545136c59bc565a35c4fc3b924ccbd69cb482f4828d6f31c"}, + {file = "grpcio-1.58.0-cp39-cp39-win_amd64.whl", hash = "sha256:dcfba7befe3a55dab6fe1eb7fc9359dc0c7f7272b30a70ae0af5d5b063842f28"}, + {file = "grpcio-1.58.0.tar.gz", hash = "sha256:532410c51ccd851b706d1fbc00a87be0f5312bd6f8e5dbf89d4e99c7f79d7499"}, +] + +[[package]] +name = "grpcio-status" +version = "1.58.0" +requires_python = ">=3.6" +summary = "Status proto mapping for gRPC" +groups = ["default"] +dependencies = [ + "googleapis-common-protos>=1.5.5", + "grpcio>=1.58.0", + "protobuf>=4.21.6", +] +files = [ + {file = "grpcio-status-1.58.0.tar.gz", hash = "sha256:0b42e70c0405a66a82d9e9867fa255fe59e618964a6099b20568c31dd9099766"}, + {file = "grpcio_status-1.58.0-py3-none-any.whl", hash = "sha256:36d46072b71a00147709ebce49344ac59b4b8960942acf0f813a8a7d6c1c28e0"}, +] + +[[package]] +name = "grpcio-tools" +version = "1.58.0" +requires_python = ">=3.7" +summary = "Protobuf code generator for gRPC" +groups = ["default"] +dependencies = [ + "grpcio>=1.58.0", + "protobuf<5.0dev,>=4.21.6", + "setuptools", +] +files = [ + {file = "grpcio-tools-1.58.0.tar.gz", hash = "sha256:6f4d80ceb591e31ca4dceec747dbe56132e1392a0a9bb1c8fe001d1b5cac898a"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:60c874908f3b40f32f1bb0221f7b3ab65ecb53a4d0a9f0a394f031f1b292c177"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:1852e798f31e5437ca7b37abc910e028b34732fb19364862cedb87b1dab66fad"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:149fb48f53cb691a6328f68bed8e4036c730f7106b7f98e92c2c0403f0b9e93c"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba3d383e5ca93826038b70f326fce8e8d12dd9b2f64d363a3d612f7475f12dd2"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6997511e9d2979f7a2389479682dbb06823f21a904e8fb0a5c6baaf1b4b4a863"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8de0b701da479643f71fad71fe66885cddd89441ae16e2c724939b47742dc72e"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:43cc23908b63fcaefe690b10f68a2d8652c994b5b36ab77d2271d9608c895320"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-win32.whl", hash = "sha256:2c2221123d010dc6231799e63a37f2f4786bf614ef65b23009c387cd20d8b193"}, + {file = "grpcio_tools-1.58.0-cp310-cp310-win_amd64.whl", hash = "sha256:df2788736bdf58abe7b0e4d6b1ff806f7686c98c5ad900da312252e3322d91c4"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:b6ea5578712cdb29b0ff60bfc6405bf0e8d681b9c71d106dd1cda54fe7fe4e55"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:c29880f491581c83181c0a84a4d11402af2b13166a5266f64e246adf1da7aa66"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:32d51e933c3565414dd0835f930bb28a1cdeba435d9d2c87fa3cf8b1d284db3c"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ad9d77f25514584b1ddc981d70c9e50dfcfc388aa5ba943eee67520c5267ed9"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4882382631e6352819059278a5c878ce0b067008dd490911d16d5616e8a36d85"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d84091a189d848d94645b7c48b61734c12ec03b0d46e5fc0049343a26989ac5c"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:85ac28a9621e9b92a3fc416288c4ce45542db0b4c31b3e23031dd8e0a0ec5590"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-win32.whl", hash = "sha256:7371d8ea80234b29affec145e25569523f549520ed7e53b2aa92bed412cdecfd"}, + {file = "grpcio_tools-1.58.0-cp311-cp311-win_amd64.whl", hash = "sha256:6997df6e7c5cf4d3ddc764240c1ff6a04b45d70ec28913b38fbc6396ef743e12"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:46628247fbce86d18232eead24bd22ed0826c79f3fe2fc2fbdbde45971361049"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:51587842a54e025a3d0d37afcf4ef2b7ac1def9a5d17448665cb424b53d6c287"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:a062ae3072a2a39a3c057f4d68b57b021f1dd2956cd09aab39709f6af494e1de"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eec3c93a08df11c80ef1c29a616bcbb0d83dbc6ea41b48306fcacc720416dfa7"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b63f823ac991ff77104da614d2a2485a59d37d57830eb2e387a6e2a3edc7fa2b"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:579c11a9f198847ed48dbc4f211c67fe96a73320b87c81f01b044b72e24a7d77"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6ca2fc1dd8049d417a5034d944c9df05cee76f855b3e431627ab4292e7c01c47"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-win32.whl", hash = "sha256:453023120114c35d3d9d6717ea0820e5d5c140f51f9d0b621de4397ff854471b"}, + {file = "grpcio_tools-1.58.0-cp39-cp39-win_amd64.whl", hash = "sha256:b6c896f1df99c35cf062d4803c15663ff00a33ff09add28baa6e475cf6b5e258"}, +] + +[[package]] +name = "gunicorn" +version = "21.2.0" +requires_python = ">=3.5" +summary = "WSGI HTTP Server for UNIX" +groups = ["deploy"] +dependencies = [ + "packaging", +] +files = [ + {file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"}, + {file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"}, +] + +[[package]] +name = "h11" +version = "0.14.0" +requires_python = ">=3.7" +summary = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +groups = ["default"] +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 = "h2" +version = "4.1.0" +requires_python = ">=3.6.1" +summary = "HTTP/2 State-Machine based protocol implementation" +groups = ["default"] +dependencies = [ + "hpack<5,>=4.0", + "hyperframe<7,>=6.0", +] +files = [ + {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, + {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, +] + +[[package]] +name = "halo" +version = "0.0.31" +requires_python = ">=3.4" +summary = "Beautiful terminal spinners in Python" +groups = ["default"] +dependencies = [ + "colorama>=0.3.9", + "log-symbols>=0.0.14", + "six>=1.12.0", + "spinners>=0.0.24", + "termcolor>=1.1.0", +] +files = [ + {file = "halo-0.0.31.tar.gz", hash = "sha256:7b67a3521ee91d53b7152d4ee3452811e1d2a6321975137762eb3d70063cc9d6"}, +] + +[[package]] +name = "hpack" +version = "4.0.0" +requires_python = ">=3.6.1" +summary = "Pure-Python HPACK header compression" +groups = ["default"] +files = [ + {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, + {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, +] + +[[package]] +name = "httpcore" +version = "0.17.3" +requires_python = ">=3.7" +summary = "A minimal low-level HTTP client." +groups = ["default"] +dependencies = [ + "anyio<5.0,>=3.0", + "certifi", + "h11<0.15,>=0.13", + "sniffio==1.*", +] +files = [ + {file = "httpcore-0.17.3-py3-none-any.whl", hash = "sha256:c2789b767ddddfa2a5782e3199b2b7f6894540b17b16ec26b2c4d8e103510b87"}, + {file = "httpcore-0.17.3.tar.gz", hash = "sha256:a6f30213335e34c1ade7be6ec7c47f19f50c56db36abef1a9dfa3815b1cb3888"}, +] + +[[package]] +name = "httplib2" +version = "0.22.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +summary = "A comprehensive HTTP client library." +groups = ["default"] +dependencies = [ + "pyparsing!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3,<4,>=2.4.2; python_version > \"3.0\"", +] +files = [ + {file = "httplib2-0.22.0-py3-none-any.whl", hash = "sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc"}, + {file = "httplib2-0.22.0.tar.gz", hash = "sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81"}, +] + +[[package]] +name = "httpx" +version = "0.24.1" +requires_python = ">=3.7" +summary = "The next generation HTTP client." +groups = ["default"] +dependencies = [ + "certifi", + "httpcore<0.18.0,>=0.15.0", + "idna", + "sniffio", +] +files = [ + {file = "httpx-0.24.1-py3-none-any.whl", hash = "sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd"}, + {file = "httpx-0.24.1.tar.gz", hash = "sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd"}, +] + +[[package]] +name = "httpx" +version = "0.24.1" +extras = ["http2"] +requires_python = ">=3.7" +summary = "The next generation HTTP client." +groups = ["default"] +dependencies = [ + "h2<5,>=3", + "httpx==0.24.1", +] +files = [ + {file = "httpx-0.24.1-py3-none-any.whl", hash = "sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd"}, + {file = "httpx-0.24.1.tar.gz", hash = "sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd"}, +] + +[[package]] +name = "huggingface" +version = "0.0.1" +summary = "HuggingFace is a single library comprising the main HuggingFace libraries." +groups = ["default"] +files = [ + {file = "huggingface-0.0.1-py3-none-any.whl", hash = "sha256:98a3409537557cd2fd768997ef94cab08529f86c5e106e6d54bbabdd5ee03910"}, + {file = "huggingface-0.0.1.tar.gz", hash = "sha256:0a2f228fd956801d68b7c6a8bef478dfa60c4b7d7eba572ea7de39ecf87e505a"}, +] + +[[package]] +name = "huggingface-hub" +version = "0.19.4" +requires_python = ">=3.8.0" +summary = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" +groups = ["default"] +dependencies = [ + "filelock", + "fsspec>=2023.5.0", + "packaging>=20.9", + "pyyaml>=5.1", + "requests", + "tqdm>=4.42.1", + "typing-extensions>=3.7.4.3", +] +files = [ + {file = "huggingface_hub-0.19.4-py3-none-any.whl", hash = "sha256:dba013f779da16f14b606492828f3760600a1e1801432d09fe1c33e50b825bb5"}, + {file = "huggingface_hub-0.19.4.tar.gz", hash = "sha256:176a4fc355a851c17550e7619488f383189727eab209534d7cef2114dae77b22"}, +] + +[[package]] +name = "humanfriendly" +version = "10.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +summary = "Human friendly output for text interfaces using Python" +groups = ["default"] +dependencies = [ + "pyreadline3; sys_platform == \"win32\" and python_version >= \"3.8\"", +] +files = [ + {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"}, + {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"}, +] + +[[package]] +name = "humanize" +version = "4.9.0" +requires_python = ">=3.8" +summary = "Python humanize utilities" +groups = ["default"] +files = [ + {file = "humanize-4.9.0-py3-none-any.whl", hash = "sha256:ce284a76d5b1377fd8836733b983bfb0b76f1aa1c090de2566fcf008d7f6ab16"}, + {file = "humanize-4.9.0.tar.gz", hash = "sha256:582a265c931c683a7e9b8ed9559089dea7edcf6cc95be39a3cbc2c5d5ac2bcfa"}, +] + +[[package]] +name = "hyperframe" +version = "6.0.1" +requires_python = ">=3.6.1" +summary = "HTTP/2 framing layer for Python" +groups = ["default"] +files = [ + {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, + {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, +] + +[[package]] +name = "idna" +version = "3.6" +requires_python = ">=3.5" +summary = "Internationalized Domain Names in Applications (IDNA)" +groups = ["default"] +files = [ + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, +] + +[[package]] +name = "inflection" +version = "0.5.1" +requires_python = ">=3.5" +summary = "A port of Ruby on Rails inflector to Python" +groups = ["default"] +files = [ + {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, + {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +requires_python = ">=3.7" +summary = "brain-dead simple config-ini parsing" +groups = ["test"] +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 = "jmespath" +version = "1.0.1" +requires_python = ">=3.7" +summary = "JSON Matching Expressions" +groups = ["default"] +files = [ + {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, + {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, +] + +[[package]] +name = "joblib" +version = "1.3.2" +requires_python = ">=3.7" +summary = "Lightweight pipelining with Python functions" +groups = ["default"] +files = [ + {file = "joblib-1.3.2-py3-none-any.whl", hash = "sha256:ef4331c65f239985f3f2220ecc87db222f08fd22097a3dd5698f693875f8cbb9"}, + {file = "joblib-1.3.2.tar.gz", hash = "sha256:92f865e621e17784e7955080b6d042489e3b8e294949cc44c6eac304f59772b1"}, +] + +[[package]] +name = "jsonpatch" +version = "1.33" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +summary = "Apply JSON-Patches (RFC 6902) " +groups = ["default"] +dependencies = [ + "jsonpointer>=1.9", +] +files = [ + {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"}, + {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"}, +] + +[[package]] +name = "jsonpointer" +version = "2.4" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +summary = "Identify specific nodes in a JSON document (RFC 6901) " +groups = ["default"] +files = [ + {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"}, + {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"}, +] + +[[package]] +name = "jsonschema" +version = "4.18.6" +requires_python = ">=3.8" +summary = "An implementation of JSON Schema validation for Python" +groups = ["default"] +dependencies = [ + "attrs>=22.2.0", + "jsonschema-specifications>=2023.03.6", + "referencing>=0.28.4", + "rpds-py>=0.7.1", +] +files = [ + {file = "jsonschema-4.18.6-py3-none-any.whl", hash = "sha256:dc274409c36175aad949c68e5ead0853aaffbe8e88c830ae66bb3c7a1728ad2d"}, + {file = "jsonschema-4.18.6.tar.gz", hash = "sha256:ce71d2f8c7983ef75a756e568317bf54bc531dc3ad7e66a128eae0d51623d8a3"}, +] + +[[package]] +name = "jsonschema-specifications" +version = "2023.12.1" +requires_python = ">=3.8" +summary = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +groups = ["default"] +dependencies = [ + "referencing>=0.31.0", +] +files = [ + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, +] + +[[package]] +name = "kombu" +version = "5.3.5" +requires_python = ">=3.8" +summary = "Messaging library for Python." +groups = ["default"] +dependencies = [ + "amqp<6.0.0,>=5.1.1", + "typing-extensions; python_version < \"3.10\"", + "vine", +] +files = [ + {file = "kombu-5.3.5-py3-none-any.whl", hash = "sha256:0eac1bbb464afe6fb0924b21bf79460416d25d8abc52546d4f16cad94f789488"}, + {file = "kombu-5.3.5.tar.gz", hash = "sha256:30e470f1a6b49c70dc6f6d13c3e4cc4e178aa6c469ceb6bcd55645385fc84b93"}, +] + +[[package]] +name = "llama-index" +version = "0.9.28" +requires_python = ">=3.8.1,<4.0" +summary = "Interface between LLMs and your data" +groups = ["default"] +dependencies = [ + "SQLAlchemy[asyncio]>=1.4.49", + "aiohttp<4.0.0,>=3.8.6", + "beautifulsoup4<5.0.0,>=4.12.2", + "dataclasses-json", + "deprecated>=1.2.9.3", + "fsspec>=2023.5.0", + "httpx", + "nest-asyncio<2.0.0,>=1.5.8", + "networkx>=3.0", + "nltk<4.0.0,>=3.8.1", + "numpy", + "openai>=1.1.0", + "pandas", + "requests>=2.31.0", + "tenacity<9.0.0,>=8.2.0", + "tensorrt-llm<0.8.0,>=0.7.1; python_version == \"3.10\"", + "tiktoken>=0.3.3", + "typing-extensions>=4.5.0", + "typing-inspect>=0.8.0", +] +files = [ + {file = "llama_index-0.9.28-py3-none-any.whl", hash = "sha256:fe68d102e9796eac54e7b6e4bc470fa63e0f4b8df6570f9ca7e0b2a644ffd49a"}, + {file = "llama_index-0.9.28.tar.gz", hash = "sha256:32504aac009c9c5addee36a5368cf4c308a898738bb2135bfcd032874f4dba26"}, +] + +[[package]] +name = "log-symbols" +version = "0.0.14" +summary = "Colored symbols for various log levels for Python" +groups = ["default"] +dependencies = [ + "colorama>=0.3.9", +] +files = [ + {file = "log_symbols-0.0.14-py3-none-any.whl", hash = "sha256:4952106ff8b605ab7d5081dd2c7e6ca7374584eff7086f499c06edd1ce56dcca"}, + {file = "log_symbols-0.0.14.tar.gz", hash = "sha256:cf0bbc6fe1a8e53f0d174a716bc625c4f87043cc21eb55dd8a740cfe22680556"}, +] + +[[package]] +name = "loguru" +version = "0.7.2" +requires_python = ">=3.5" +summary = "Python logging made (stupidly) simple" +groups = ["default"] +dependencies = [ + "colorama>=0.3.4; sys_platform == \"win32\"", + "win32-setctime>=1.0.0; sys_platform == \"win32\"", +] +files = [ + {file = "loguru-0.7.2-py3-none-any.whl", hash = "sha256:003d71e3d3ed35f0f8984898359d65b79e5b21943f78af86aa5491210429b8eb"}, + {file = "loguru-0.7.2.tar.gz", hash = "sha256:e671a53522515f34fd406340ee968cb9ecafbc4b36c679da03c18fd8d0bd51ac"}, +] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +requires_python = ">=3.8" +summary = "Python port of markdown-it. Markdown parsing, done right!" +groups = ["default"] +dependencies = [ + "mdurl~=0.1", +] +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]] +name = "marshmallow" +version = "3.20.2" +requires_python = ">=3.8" +summary = "A lightweight library for converting complex datatypes to and from native Python datatypes." +groups = ["default"] +dependencies = [ + "packaging>=17.0", +] +files = [ + {file = "marshmallow-3.20.2-py3-none-any.whl", hash = "sha256:c21d4b98fee747c130e6bc8f45c4b3199ea66bc00c12ee1f639f0aeca034d5e9"}, + {file = "marshmallow-3.20.2.tar.gz", hash = "sha256:4c1daff273513dc5eb24b219a8035559dc573c8f322558ef85f5438ddd1236dd"}, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +requires_python = ">=3.7" +summary = "Markdown URL utilities" +groups = ["default"] +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 = "minio" +version = "7.2.4" +summary = "MinIO Python SDK for Amazon S3 Compatible Cloud Storage" +groups = ["default"] +dependencies = [ + "argon2-cffi", + "certifi", + "pycryptodome", + "typing-extensions", + "urllib3", +] +files = [ + {file = "minio-7.2.4-py3-none-any.whl", hash = "sha256:91b51c21d25e3ee6d51f52eab126d6c974371add0d77951e42c322a59c5533e7"}, + {file = "minio-7.2.4.tar.gz", hash = "sha256:d504d8464e5198fb74dd9b572cc88b185ae7997c17705e8c09f3fef2f439d984"}, +] + +[[package]] +name = "mistralai" +version = "0.0.8" +requires_python = ">=3.8,<4.0" +summary = "" +groups = ["default"] +dependencies = [ + "aiohttp<4.0.0,>=3.9.1", + "backoff<3.0.0,>=2.2.1", + "orjson<4.0.0,>=3.9.10", + "pydantic<3.0.0,>=2.5.2", + "requests<3.0.0,>=2.31.0", +] +files = [ + {file = "mistralai-0.0.8-py3-none-any.whl", hash = "sha256:288d31c30d40aacef46c98f05676813153938e36e1a3d49c3943eba227faf8b3"}, + {file = "mistralai-0.0.8.tar.gz", hash = "sha256:c1d9f53f75d6b99f614ce3d08cf90d99927c1af73ec986859ebe058431a18a5b"}, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +summary = "Python library for arbitrary-precision floating-point arithmetic" +groups = ["default"] +files = [ + {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, + {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, +] + +[[package]] +name = "multidict" +version = "6.0.5" +requires_python = ">=3.7" +summary = "multidict implementation" +groups = ["default"] +files = [ + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, + {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, + {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, + {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, + {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, + {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, + {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, + {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, + {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +requires_python = ">=3.5" +summary = "Type system extensions for programs checked with the mypy type checker." +groups = ["default"] +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" +requires_python = ">=3.5" +summary = "Patch asyncio to allow nested event loops" +groups = ["default"] +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 = "networkx" +version = "3.2.1" +requires_python = ">=3.9" +summary = "Python package for creating and manipulating graphs and networks" +groups = ["default"] +files = [ + {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, + {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, +] + +[[package]] +name = "nltk" +version = "3.8.1" +requires_python = ">=3.7" +summary = "Natural Language Toolkit" +groups = ["default"] +dependencies = [ + "click", + "joblib", + "regex>=2021.8.3", + "tqdm", +] +files = [ + {file = "nltk-3.8.1-py3-none-any.whl", hash = "sha256:fd5c9109f976fa86bcadba8f91e47f5e9293bd034474752e92a520f81c93dda5"}, + {file = "nltk-3.8.1.zip", hash = "sha256:1834da3d0682cba4f2cede2f9aad6b0fafb6461ba451db0efb6f9c39798d64d3"}, +] + +[[package]] +name = "numpy" +version = "1.26.4" +requires_python = ">=3.9" +summary = "Fundamental package for array computing in Python" +groups = ["default"] +files = [ + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, +] + +[[package]] +name = "oauth2client" +version = "4.1.3" +summary = "OAuth 2.0 client library" +groups = ["default"] +dependencies = [ + "httplib2>=0.9.1", + "pyasn1-modules>=0.0.5", + "pyasn1>=0.1.7", + "rsa>=3.1.4", + "six>=1.6.1", +] +files = [ + {file = "oauth2client-4.1.3-py2.py3-none-any.whl", hash = "sha256:b8a81cc5d60e2d364f0b1b98f958dbd472887acaf1a5b05e21c28c31a2d6d3ac"}, + {file = "oauth2client-4.1.3.tar.gz", hash = "sha256:d486741e451287f69568a4d26d70d9acd73a2bbfa275746c535b4209891cccc6"}, +] + +[[package]] +name = "oauthlib" +version = "3.2.2" +requires_python = ">=3.6" +summary = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" +groups = ["default"] +files = [ + {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, + {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, +] + +[[package]] +name = "onnx" +version = "1.15.0" +requires_python = ">=3.8" +summary = "Open Neural Network Exchange" +groups = ["default"] +dependencies = [ + "numpy", + "protobuf>=3.20.2", +] +files = [ + {file = "onnx-1.15.0-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:51cacb6aafba308aaf462252ced562111f6991cdc7bc57a6c554c3519453a8ff"}, + {file = "onnx-1.15.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:0aee26b6f7f7da7e840de75ad9195a77a147d0662c94eaa6483be13ba468ffc1"}, + {file = "onnx-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baf6ef6c93b3b843edb97a8d5b3d229a1301984f3f8dee859c29634d2083e6f9"}, + {file = "onnx-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ed899fe6000edc05bb2828863d3841cfddd5a7cf04c1a771f112e94de75d9f"}, + {file = "onnx-1.15.0-cp310-cp310-win32.whl", hash = "sha256:f1ad3d77fc2f4b4296f0ac2c8cadd8c1dcf765fc586b737462d3a0fe8f7c696a"}, + {file = "onnx-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:ca4ebc4f47109bfb12c8c9e83dd99ec5c9f07d2e5f05976356c6ccdce3552010"}, + {file = "onnx-1.15.0-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:233ffdb5ca8cc2d960b10965a763910c0830b64b450376da59207f454701f343"}, + {file = "onnx-1.15.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:51fa79c9ea9af033638ec51f9177b8e76c55fad65bb83ea96ee88fafade18ee7"}, + {file = "onnx-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f277d4861729f5253a51fa41ce91bfec1c4574ee41b5637056b43500917295ce"}, + {file = "onnx-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8a7c94d2ebead8f739fdb70d1ce5a71726f4e17b3e5b8ad64455ea1b2801a85"}, + {file = "onnx-1.15.0-cp311-cp311-win32.whl", hash = "sha256:17dcfb86a8c6bdc3971443c29b023dd9c90ff1d15d8baecee0747a6b7f74e650"}, + {file = "onnx-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:60a3e28747e305cd2e766e6a53a0a6d952cf9e72005ec6023ce5e07666676a4e"}, + {file = "onnx-1.15.0-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:b2d5e802837629fc9c86f19448d19dd04d206578328bce202aeb3d4bedab43c4"}, + {file = "onnx-1.15.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:9a9cfbb5e5d5d88f89d0dfc9df5fb858899db874e1d5ed21e76c481f3cafc90d"}, + {file = "onnx-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f472bbe5cb670a0a4a4db08f41fde69b187a009d0cb628f964840d3f83524e9"}, + {file = "onnx-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bf2de9bef64792e5b8080c678023ac7d2b9e05d79a3e17e92cf6a4a624831d2"}, + {file = "onnx-1.15.0-cp39-cp39-win32.whl", hash = "sha256:ef4d9eb44b111e69e4534f3233fc2c13d1e26920d24ae4359d513bd54694bc6d"}, + {file = "onnx-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:95d7a3e2d79d371e272e39ae3f7547e0b116d0c7f774a4004e97febe6c93507f"}, + {file = "onnx-1.15.0.tar.gz", hash = "sha256:b18461a7d38f286618ca2a6e78062a2a9c634ce498e631e708a8041b00094825"}, +] + +[[package]] +name = "onnxruntime" +version = "1.17.0" +summary = "ONNX Runtime is a runtime accelerator for Machine Learning models" +groups = ["default"] +dependencies = [ + "coloredlogs", + "flatbuffers", + "numpy>=1.21.6", + "packaging", + "protobuf", + "sympy", +] +files = [ + {file = "onnxruntime-1.17.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:d2b22a25a94109cc983443116da8d9805ced0256eb215c5e6bc6dcbabefeab96"}, + {file = "onnxruntime-1.17.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4c87d83c6f58d1af2675fc99e3dc810f2dbdb844bcefd0c1b7573632661f6fc"}, + {file = "onnxruntime-1.17.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dba55723bf9b835e358f48c98a814b41692c393eb11f51e02ece0625c756b797"}, + {file = "onnxruntime-1.17.0-cp310-cp310-win32.whl", hash = "sha256:ee48422349cc500273beea7607e33c2237909f58468ae1d6cccfc4aecd158565"}, + {file = "onnxruntime-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f34cc46553359293854e38bdae2ab1be59543aad78a6317e7746d30e311110c3"}, + {file = "onnxruntime-1.17.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:16d26badd092c8c257fa57c458bb600d96dc15282c647ccad0ed7b2732e6c03b"}, + {file = "onnxruntime-1.17.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f1273bebcdb47ed932d076c85eb9488bc4768fcea16d5f2747ca692fad4f9d3"}, + {file = "onnxruntime-1.17.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cb60fd3c2c1acd684752eb9680e89ae223e9801a9b0e0dc7b28adabe45a2e380"}, + {file = "onnxruntime-1.17.0-cp311-cp311-win32.whl", hash = "sha256:4b038324586bc905299e435f7c00007e6242389c856b82fe9357fdc3b1ef2bdc"}, + {file = "onnxruntime-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:93d39b3fa1ee01f034f098e1c7769a811a21365b4883f05f96c14a2b60c6028b"}, + {file = "onnxruntime-1.17.0-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:5a06ab84eaa350bf64b1d747b33ccf10da64221ed1f38f7287f15eccbec81603"}, + {file = "onnxruntime-1.17.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d3d11db2c8242766212a68d0b139745157da7ce53bd96ba349a5c65e5a02357"}, + {file = "onnxruntime-1.17.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5632077c3ab8b0cd4f74b0af9c4e924be012b1a7bcd7daa845763c6c6bf14b7d"}, + {file = "onnxruntime-1.17.0-cp39-cp39-win32.whl", hash = "sha256:61a12732cba869b3ad2d4e29ab6cb62c7a96f61b8c213f7fcb961ba412b70b37"}, + {file = "onnxruntime-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:461fa0fc7d9c392c352b6cccdedf44d818430f3d6eacd924bb804fdea2dcfd02"}, +] + +[[package]] +name = "openai" +version = "1.3.9" +requires_python = ">=3.7.1" +summary = "The official Python library for the openai API" +groups = ["default"] +dependencies = [ + "anyio<5,>=3.5.0", + "distro<2,>=1.7.0", + "httpx<1,>=0.23.0", + "pydantic<3,>=1.9.0", + "sniffio", + "tqdm>4", + "typing-extensions<5,>=4.5", +] +files = [ + {file = "openai-1.3.9-py3-none-any.whl", hash = "sha256:d30faeffe5995a2cf6b790c0260a5b59647e81c3a1f3b62f51b5e0a0e52681c9"}, + {file = "openai-1.3.9.tar.gz", hash = "sha256:6f638d96bc89b4394be1d7b37d312f70a055df1a471c92d4c4b2ae3a70c98cb3"}, +] + +[[package]] +name = "orjson" +version = "3.9.15" +requires_python = ">=3.8" +summary = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +groups = ["default"] +files = [ + {file = "orjson-3.9.15-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d61f7ce4727a9fa7680cd6f3986b0e2c732639f46a5e0156e550e35258aa313a"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4feeb41882e8aa17634b589533baafdceb387e01e117b1ec65534ec724023d04"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fbbeb3c9b2edb5fd044b2a070f127a0ac456ffd079cb82746fc84af01ef021a4"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b66bcc5670e8a6b78f0313bcb74774c8291f6f8aeef10fe70e910b8040f3ab75"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2973474811db7b35c30248d1129c64fd2bdf40d57d84beed2a9a379a6f57d0ab"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fe41b6f72f52d3da4db524c8653e46243c8c92df826ab5ffaece2dba9cccd58"}, + {file = "orjson-3.9.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4228aace81781cc9d05a3ec3a6d2673a1ad0d8725b4e915f1089803e9efd2b99"}, + {file = "orjson-3.9.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6f7b65bfaf69493c73423ce9db66cfe9138b2f9ef62897486417a8fcb0a92bfe"}, + {file = "orjson-3.9.15-cp310-none-win32.whl", hash = "sha256:2d99e3c4c13a7b0fb3792cc04c2829c9db07838fb6973e578b85c1745e7d0ce7"}, + {file = "orjson-3.9.15-cp310-none-win_amd64.whl", hash = "sha256:b725da33e6e58e4a5d27958568484aa766e825e93aa20c26c91168be58e08cbb"}, + {file = "orjson-3.9.15-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c8e8fe01e435005d4421f183038fc70ca85d2c1e490f51fb972db92af6e047c2"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87f1097acb569dde17f246faa268759a71a2cb8c96dd392cd25c668b104cad2f"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff0f9913d82e1d1fadbd976424c316fbc4d9c525c81d047bbdd16bd27dd98cfc"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8055ec598605b0077e29652ccfe9372247474375e0e3f5775c91d9434e12d6b1"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d6768a327ea1ba44c9114dba5fdda4a214bdb70129065cd0807eb5f010bfcbb5"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12365576039b1a5a47df01aadb353b68223da413e2e7f98c02403061aad34bde"}, + {file = "orjson-3.9.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:71c6b009d431b3839d7c14c3af86788b3cfac41e969e3e1c22f8a6ea13139404"}, + {file = "orjson-3.9.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e18668f1bd39e69b7fed19fa7cd1cd110a121ec25439328b5c89934e6d30d357"}, + {file = "orjson-3.9.15-cp311-none-win32.whl", hash = "sha256:62482873e0289cf7313461009bf62ac8b2e54bc6f00c6fabcde785709231a5d7"}, + {file = "orjson-3.9.15-cp311-none-win_amd64.whl", hash = "sha256:b3d336ed75d17c7b1af233a6561cf421dee41d9204aa3cfcc6c9c65cd5bb69a8"}, + {file = "orjson-3.9.15-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6fc2fe4647927070df3d93f561d7e588a38865ea0040027662e3e541d592811e"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34cbcd216e7af5270f2ffa63a963346845eb71e174ea530867b7443892d77180"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f541587f5c558abd93cb0de491ce99a9ef8d1ae29dd6ab4dbb5a13281ae04cbd"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92255879280ef9c3c0bcb327c5a1b8ed694c290d61a6a532458264f887f052cb"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:05a1f57fb601c426635fcae9ddbe90dfc1ed42245eb4c75e4960440cac667262"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ede0bde16cc6e9b96633df1631fbcd66491d1063667f260a4f2386a098393790"}, + {file = "orjson-3.9.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e88b97ef13910e5f87bcbc4dd7979a7de9ba8702b54d3204ac587e83639c0c2b"}, + {file = "orjson-3.9.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57d5d8cf9c27f7ef6bc56a5925c7fbc76b61288ab674eb352c26ac780caa5b10"}, + {file = "orjson-3.9.15-cp39-none-win32.whl", hash = "sha256:001f4eb0ecd8e9ebd295722d0cbedf0748680fb9998d3993abaed2f40587257a"}, + {file = "orjson-3.9.15-cp39-none-win_amd64.whl", hash = "sha256:ea0b183a5fe6b2b45f3b854b0d19c4e932d6f5934ae1f723b07cf9560edd4ec7"}, + {file = "orjson-3.9.15.tar.gz", hash = "sha256:95cae920959d772f30ab36d3b25f83bb0f3be671e986c72ce22f8fa700dae061"}, +] + +[[package]] +name = "packaging" +version = "23.2" +requires_python = ">=3.7" +summary = "Core utilities for Python packages" +groups = ["default", "deploy", "test"] +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pandas" +version = "2.1.4" +requires_python = ">=3.9" +summary = "Powerful data structures for data analysis, time series, and statistics" +groups = ["default"] +dependencies = [ + "numpy<2,>=1.22.4; python_version < \"3.11\"", + "numpy<2,>=1.23.2; python_version == \"3.11\"", + "python-dateutil>=2.8.2", + "pytz>=2020.1", + "tzdata>=2022.1", +] +files = [ + {file = "pandas-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bdec823dc6ec53f7a6339a0e34c68b144a7a1fd28d80c260534c39c62c5bf8c9"}, + {file = "pandas-2.1.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:294d96cfaf28d688f30c918a765ea2ae2e0e71d3536754f4b6de0ea4a496d034"}, + {file = "pandas-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b728fb8deba8905b319f96447a27033969f3ea1fea09d07d296c9030ab2ed1d"}, + {file = "pandas-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00028e6737c594feac3c2df15636d73ace46b8314d236100b57ed7e4b9ebe8d9"}, + {file = "pandas-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:426dc0f1b187523c4db06f96fb5c8d1a845e259c99bda74f7de97bd8a3bb3139"}, + {file = "pandas-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:f237e6ca6421265643608813ce9793610ad09b40154a3344a088159590469e46"}, + {file = "pandas-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b7d852d16c270e4331f6f59b3e9aa23f935f5c4b0ed2d0bc77637a8890a5d092"}, + {file = "pandas-2.1.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd7d5f2f54f78164b3d7a40f33bf79a74cdee72c31affec86bfcabe7e0789821"}, + {file = "pandas-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0aa6e92e639da0d6e2017d9ccff563222f4eb31e4b2c3cf32a2a392fc3103c0d"}, + {file = "pandas-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d797591b6846b9db79e65dc2d0d48e61f7db8d10b2a9480b4e3faaddc421a171"}, + {file = "pandas-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2d3e7b00f703aea3945995ee63375c61b2e6aa5aa7871c5d622870e5e137623"}, + {file = "pandas-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:dc9bf7ade01143cddc0074aa6995edd05323974e6e40d9dbde081021ded8510e"}, + {file = "pandas-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3f06bda01a143020bad20f7a85dd5f4a1600112145f126bc9e3e42077c24ef34"}, + {file = "pandas-2.1.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab5796839eb1fd62a39eec2916d3e979ec3130509930fea17fe6f81e18108f6a"}, + {file = "pandas-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edbaf9e8d3a63a9276d707b4d25930a262341bca9874fcb22eff5e3da5394732"}, + {file = "pandas-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ebfd771110b50055712b3b711b51bee5d50135429364d0498e1213a7adc2be8"}, + {file = "pandas-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8ea107e0be2aba1da619cc6ba3f999b2bfc9669a83554b1904ce3dd9507f0860"}, + {file = "pandas-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:d65148b14788b3758daf57bf42725caa536575da2b64df9964c563b015230984"}, + {file = "pandas-2.1.4.tar.gz", hash = "sha256:fcb68203c833cc735321512e13861358079a96c174a61f5116a1de89c58c0ef7"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +requires_python = ">=3.8" +summary = "Utility library for gitignore style pattern matching of file paths." +groups = ["default"] +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 = "pdfminer-six" +version = "20221105" +requires_python = ">=3.6" +summary = "PDF parser and analyzer" +groups = ["default"] +dependencies = [ + "charset-normalizer>=2.0.0", + "cryptography>=36.0.0", +] +files = [ + {file = "pdfminer.six-20221105-py3-none-any.whl", hash = "sha256:1eaddd712d5b2732f8ac8486824533514f8ba12a0787b3d5fe1e686cd826532d"}, + {file = "pdfminer.six-20221105.tar.gz", hash = "sha256:8448ab7b939d18b64820478ecac5394f482d7a79f5f7eaa7703c6c959c175e1d"}, +] + +[[package]] +name = "pdfplumber" +version = "0.10.3" +requires_python = ">=3.8" +summary = "Plumb a PDF for detailed information about each char, rectangle, and line." +groups = ["default"] +dependencies = [ + "Pillow>=9.1", + "pdfminer-six==20221105", + "pypdfium2>=4.18.0", +] +files = [ + {file = "pdfplumber-0.10.3-py3-none-any.whl", hash = "sha256:7cb73f382278967db8d0e681f67aca82b41c32861df1d85f9f6a2cf18a175fa8"}, + {file = "pdfplumber-0.10.3.tar.gz", hash = "sha256:4dd78ff1c62b99da8139daf5b62747613f6f0e970f225a3e911862e296599375"}, +] + +[[package]] +name = "pgvector" +version = "0.1.8" +requires_python = ">=3.6" +summary = "pgvector support for Python" +groups = ["default"] +dependencies = [ + "numpy", +] +files = [ + {file = "pgvector-0.1.8-py2.py3-none-any.whl", hash = "sha256:99dce3a6580ef73863edb9b8441937671f4e1a09383826e6b0838176cd441a96"}, +] + +[[package]] +name = "pillow" +version = "10.2.0" +requires_python = ">=3.8" +summary = "Python Imaging Library (Fork)" +groups = ["default"] +files = [ + {file = "pillow-10.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e"}, + {file = "pillow-10.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0"}, + {file = "pillow-10.2.0-cp310-cp310-win32.whl", hash = "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023"}, + {file = "pillow-10.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72"}, + {file = "pillow-10.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757"}, + {file = "pillow-10.2.0-cp311-cp311-win32.whl", hash = "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068"}, + {file = "pillow-10.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56"}, + {file = "pillow-10.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591"}, + {file = "pillow-10.2.0-cp39-cp39-win32.whl", hash = "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516"}, + {file = "pillow-10.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8"}, + {file = "pillow-10.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6"}, + {file = "pillow-10.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868"}, + {file = "pillow-10.2.0.tar.gz", hash = "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e"}, +] + +[[package]] +name = "pinecone-client" +version = "2.2.4" +requires_python = ">=3.8" +summary = "Pinecone client and SDK" +groups = ["default"] +dependencies = [ + "dnspython>=2.0.0", + "loguru>=0.5.0", + "numpy>=1.22.0", + "python-dateutil>=2.5.3", + "pyyaml>=5.4", + "requests>=2.19.0", + "tqdm>=4.64.1", + "typing-extensions>=3.7.4", + "urllib3>=1.21.1", +] +files = [ + {file = "pinecone-client-2.2.4.tar.gz", hash = "sha256:2c1cc1d6648b2be66e944db2ffa59166a37b9164d1135ad525d9cd8b1e298168"}, + {file = "pinecone_client-2.2.4-py3-none-any.whl", hash = "sha256:5bf496c01c2f82f4e5c2dc977cc5062ecd7168b8ed90743b09afcc8c7eb242ec"}, +] + +[[package]] +name = "platformdirs" +version = "3.11.0" +requires_python = ">=3.7" +summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +groups = ["default"] +files = [ + {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, + {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, +] + +[[package]] +name = "pluggy" +version = "1.4.0" +requires_python = ">=3.8" +summary = "plugin and hook calling mechanisms for python" +groups = ["test"] +files = [ + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, +] + +[[package]] +name = "ply" +version = "3.11" +summary = "Python Lex & Yacc" +groups = ["default"] +files = [ + {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"}, + {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, +] + +[[package]] +name = "portalocker" +version = "2.8.2" +requires_python = ">=3.8" +summary = "Wraps the portalocker recipe for easy usage" +groups = ["default"] +dependencies = [ + "pywin32>=226; platform_system == \"Windows\"", +] +files = [ + {file = "portalocker-2.8.2-py3-none-any.whl", hash = "sha256:cfb86acc09b9aa7c3b43594e19be1345b9d16af3feb08bf92f23d4dce513a28e"}, + {file = "portalocker-2.8.2.tar.gz", hash = "sha256:2b035aa7828e46c58e9b31390ee1f169b98e1066ab10b9a6a861fe7e25ee4f33"}, +] + +[[package]] +name = "postgrest" +version = "0.13.2" +requires_python = ">=3.8,<4.0" +summary = "PostgREST client for Python. This library provides an ORM interface to PostgREST." +groups = ["default"] +dependencies = [ + "deprecation<3.0.0,>=2.1.0", + "httpx<0.26,>=0.24", + "pydantic<3.0,>=1.9", + "strenum<0.5.0,>=0.4.9", +] +files = [ + {file = "postgrest-0.13.2-py3-none-any.whl", hash = "sha256:a1a120ca982617d90c8906b85e2731fac4a3a3a5c7a3ca1095fe1cebd0bc02be"}, + {file = "postgrest-0.13.2.tar.gz", hash = "sha256:aaaec0fd7e4745dc02c77e1b310689fcdfb669e43b4cb36d462221dc1d19a1bf"}, +] + +[[package]] +name = "prometheus-client" +version = "0.20.0" +requires_python = ">=3.8" +summary = "Python client for the Prometheus monitoring system." +groups = ["default"] +files = [ + {file = "prometheus_client-0.20.0-py3-none-any.whl", hash = "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7"}, + {file = "prometheus_client-0.20.0.tar.gz", hash = "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89"}, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.43" +requires_python = ">=3.7.0" +summary = "Library for building powerful interactive command lines in Python" +groups = ["default"] +dependencies = [ + "wcwidth", +] +files = [ + {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, + {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, +] + +[[package]] +name = "proto-plus" +version = "1.23.0" +requires_python = ">=3.6" +summary = "Beautiful, Pythonic protocol buffers." +groups = ["default"] +dependencies = [ + "protobuf<5.0.0dev,>=3.19.0", +] +files = [ + {file = "proto-plus-1.23.0.tar.gz", hash = "sha256:89075171ef11988b3fa157f5dbd8b9cf09d65fffee97e29ce403cd8defba19d2"}, + {file = "proto_plus-1.23.0-py3-none-any.whl", hash = "sha256:a829c79e619e1cf632de091013a4173deed13a55f326ef84f05af6f50ff4c82c"}, +] + +[[package]] +name = "protobuf" +version = "4.25.3" +requires_python = ">=3.8" +summary = "" +groups = ["default"] +files = [ + {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, + {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, + {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"}, + {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"}, + {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"}, + {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"}, + {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"}, +] + +[[package]] +name = "psycopg2-binary" +version = "2.9.9" +requires_python = ">=3.7" +summary = "psycopg2 - Python-PostgreSQL Database Adapter" +groups = ["default"] +files = [ + {file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-win32.whl", hash = "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"}, +] + +[[package]] +name = "pyarrow" +version = "15.0.0" +requires_python = ">=3.8" +summary = "Python library for Apache Arrow" +groups = ["default"] +dependencies = [ + "numpy<2,>=1.16.6", +] +files = [ + {file = "pyarrow-15.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:0a524532fd6dd482edaa563b686d754c70417c2f72742a8c990b322d4c03a15d"}, + {file = "pyarrow-15.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:60a6bdb314affa9c2e0d5dddf3d9cbb9ef4a8dddaa68669975287d47ece67642"}, + {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66958fd1771a4d4b754cd385835e66a3ef6b12611e001d4e5edfcef5f30391e2"}, + {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f500956a49aadd907eaa21d4fff75f73954605eaa41f61cb94fb008cf2e00c6"}, + {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6f87d9c4f09e049c2cade559643424da84c43a35068f2a1c4653dc5b1408a929"}, + {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85239b9f93278e130d86c0e6bb455dcb66fc3fd891398b9d45ace8799a871a1e"}, + {file = "pyarrow-15.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:5b8d43e31ca16aa6e12402fcb1e14352d0d809de70edd185c7650fe80e0769e3"}, + {file = "pyarrow-15.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:fa7cd198280dbd0c988df525e50e35b5d16873e2cdae2aaaa6363cdb64e3eec5"}, + {file = "pyarrow-15.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8780b1a29d3c8b21ba6b191305a2a607de2e30dab399776ff0aa09131e266340"}, + {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0ec198ccc680f6c92723fadcb97b74f07c45ff3fdec9dd765deb04955ccf19"}, + {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036a7209c235588c2f07477fe75c07e6caced9b7b61bb897c8d4e52c4b5f9555"}, + {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2bd8a0e5296797faf9a3294e9fa2dc67aa7f10ae2207920dbebb785c77e9dbe5"}, + {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e8ebed6053dbe76883a822d4e8da36860f479d55a762bd9e70d8494aed87113e"}, + {file = "pyarrow-15.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:17d53a9d1b2b5bd7d5e4cd84d018e2a45bc9baaa68f7e6e3ebed45649900ba99"}, + {file = "pyarrow-15.0.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:47af7036f64fce990bb8a5948c04722e4e3ea3e13b1007ef52dfe0aa8f23cf7f"}, + {file = "pyarrow-15.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93768ccfff85cf044c418bfeeafce9a8bb0cee091bd8fd19011aff91e58de540"}, + {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6ee87fd6892700960d90abb7b17a72a5abb3b64ee0fe8db6c782bcc2d0dc0b4"}, + {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:001fca027738c5f6be0b7a3159cc7ba16a5c52486db18160909a0831b063c4e4"}, + {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:d1c48648f64aec09accf44140dccb92f4f94394b8d79976c426a5b79b11d4fa7"}, + {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:972a0141be402bb18e3201448c8ae62958c9c7923dfaa3b3d4530c835ac81aed"}, + {file = "pyarrow-15.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:f01fc5cf49081426429127aa2d427d9d98e1cb94a32cb961d583a70b7c4504e6"}, + {file = "pyarrow-15.0.0.tar.gz", hash = "sha256:876858f549d540898f927eba4ef77cd549ad8d24baa3207cf1b72e5788b50e83"}, +] + +[[package]] +name = "pyasn1" +version = "0.5.1" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +summary = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" +groups = ["default"] +files = [ + {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, + {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, +] + +[[package]] +name = "pyasn1-modules" +version = "0.3.0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +summary = "A collection of ASN.1-based protocols modules" +groups = ["default"] +dependencies = [ + "pyasn1<0.6.0,>=0.4.6", +] +files = [ + {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"}, + {file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"}, +] + +[[package]] +name = "pycparser" +version = "2.21" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +summary = "C parser in Python" +groups = ["default"] +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + +[[package]] +name = "pycryptodome" +version = "3.20.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +summary = "Cryptographic library for Python" +groups = ["default"] +files = [ + {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044"}, + {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4"}, + {file = "pycryptodome-3.20.0-cp35-abi3-win32.whl", hash = "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72"}, + {file = "pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9"}, + {file = "pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a"}, + {file = "pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e"}, + {file = "pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7"}, +] + +[[package]] +name = "pydantic" +version = "2.6.2" +requires_python = ">=3.8" +summary = "Data validation using Python type hints" +groups = ["default"] +dependencies = [ + "annotated-types>=0.4.0", + "pydantic-core==2.16.3", + "typing-extensions>=4.6.1", +] +files = [ + {file = "pydantic-2.6.2-py3-none-any.whl", hash = "sha256:37a5432e54b12fecaa1049c5195f3d860a10e01bdfd24f1840ef14bd0d3aeab3"}, + {file = "pydantic-2.6.2.tar.gz", hash = "sha256:a09be1c3d28f3abe37f8a78af58284b236a92ce520105ddc91a6d29ea1176ba7"}, +] + +[[package]] +name = "pydantic-core" +version = "2.16.3" +requires_python = ">=3.8" +summary = "" +groups = ["default"] +dependencies = [ + "typing-extensions!=4.7.0,>=4.6.0", +] +files = [ + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, + {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, + {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, + {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, + {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, + {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, + {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, + {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, + {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, +] + +[[package]] +name = "pydrive2" +version = "1.15.4" +requires_python = ">=3.7" +summary = "Google Drive API made easy. Maintained fork of PyDrive." +groups = ["default"] +dependencies = [ + "PyYAML>=3.0", + "google-api-python-client>=1.12.5", + "oauth2client>=4.0.0", + "pyOpenSSL>=19.1.0", +] +files = [ + {file = "PyDrive2-1.15.4-py3-none-any.whl", hash = "sha256:91fe28e5f094a6dfff834495c4aee0041cbef979467ad27cd0d4b1f91afa8869"}, + {file = "PyDrive2-1.15.4.tar.gz", hash = "sha256:0c011b74ebc24f3c6ca72820626b77f1dfe0ae88f5740c5a5cf96e83dd79ba99"}, +] + +[[package]] +name = "pydrive2" +version = "1.15.4" +extras = ["fsspec"] +requires_python = ">=3.7" +summary = "Google Drive API made easy. Maintained fork of PyDrive." +groups = ["default"] +dependencies = [ + "PyDrive2==1.15.4", + "appdirs>=1.4.3", + "fsspec>=2021.07.0", + "funcy>=1.14", + "tqdm>=4.0.0", +] +files = [ + {file = "PyDrive2-1.15.4-py3-none-any.whl", hash = "sha256:91fe28e5f094a6dfff834495c4aee0041cbef979467ad27cd0d4b1f91afa8869"}, + {file = "PyDrive2-1.15.4.tar.gz", hash = "sha256:0c011b74ebc24f3c6ca72820626b77f1dfe0ae88f5740c5a5cf96e83dd79ba99"}, +] + +[[package]] +name = "pygments" +version = "2.17.2" +requires_python = ">=3.7" +summary = "Pygments is a syntax highlighting package written in Python." +groups = ["default"] +files = [ + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, +] + +[[package]] +name = "pyjwt" +version = "2.8.0" +requires_python = ">=3.7" +summary = "JSON Web Token implementation in Python" +groups = ["default"] +files = [ + {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, + {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, +] + +[[package]] +name = "pymilvus" +version = "2.3.4" +requires_python = ">=3.7" +summary = "Python Sdk for Milvus" +groups = ["default"] +dependencies = [ + "environs<=9.5.0", + "grpcio<=1.58.0,>=1.49.1", + "minio>=7.0.0", + "pandas>=1.2.4", + "protobuf>=3.20.0", + "pyarrow>=12.0.0", + "requests", + "ujson>=2.0.0", +] +files = [ + {file = "pymilvus-2.3.4-py3-none-any.whl", hash = "sha256:3f56a61aaafe1f255c32b92c76cf98fc6de254d15e4d1127757b4a426622f140"}, + {file = "pymilvus-2.3.4.tar.gz", hash = "sha256:4b5fdabb15901b63a6afbccb6af9ded5c0a05ccd657189e1658710ac73f09f80"}, +] + +[[package]] +name = "pymssql" +version = "2.2.8" +summary = "DB-API interface to Microsoft SQL Server for Python. (new Cython-based version)" +groups = ["default"] +files = [ + {file = "pymssql-2.2.8-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bfd7b8edef78097ccd3f52ac3f3a5c3cf0019f8a280f306cacbbb165caaf63"}, + {file = "pymssql-2.2.8-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:049f2e3de919e8e02504780a21ebbf235e21ca8ed5c7538c5b6e705aa6c43d8c"}, + {file = "pymssql-2.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dd86d8e3e346e34f3f03d12e333747b53a1daa74374a727f4714d5b82ee0dd5"}, + {file = "pymssql-2.2.8-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:508226a0df7cb6faeda9f8e84e85743690ca427d7b27af9a73d75fcf0c1eef6e"}, + {file = "pymssql-2.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:47859887adeaf184766b5e0bc845dd23611f3808f9521552063bb36eabc10092"}, + {file = "pymssql-2.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d873e553374d5b1c57fe1c43bb75e3bcc2920678db1ef26f6bfed396c7d21b30"}, + {file = "pymssql-2.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf31b8b76634c826a91f9999e15b7bfb0c051a0f53b319fd56481a67e5b903bb"}, + {file = "pymssql-2.2.8-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:821945c2214fe666fd456c61e09a29a00e7719c9e136c801bffb3a254e9c579b"}, + {file = "pymssql-2.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:cc85b609b4e60eac25fa38bbac1ff854fd2c2a276e0ca4a3614c6f97efb644bb"}, + {file = "pymssql-2.2.8-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:895041edd002a2e91d8a4faf0906b6fbfef29d9164bc6beb398421f5927fa40e"}, + {file = "pymssql-2.2.8-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6b2d9c6d38a416c6f2db36ff1cd8e69f9a5387a46f9f4f612623192e0c9404b1"}, + {file = "pymssql-2.2.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d63d6f25cf40fe6a03c49be2d4d337858362b8ab944d6684c268e4990807cf0c"}, + {file = "pymssql-2.2.8-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:c83ad3ad20951f3a94894b354fa5fa9666dcd5ebb4a635dad507c7d1dd545833"}, + {file = "pymssql-2.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3933f7f082be74698eea835df51798dab9bc727d94d3d280bffc75ab9265f890"}, + {file = "pymssql-2.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:de313375b90b0f554058992f35c4a4beb3f6ec2f5912d8cd6afb649f95b03a9f"}, + {file = "pymssql-2.2.8.tar.gz", hash = "sha256:9baefbfbd07d0142756e2dfcaa804154361ac5806ab9381350aad4e780c3033e"}, +] + +[[package]] +name = "pymysql" +version = "1.1.0" +requires_python = ">=3.7" +summary = "Pure Python MySQL Driver" +groups = ["default"] +files = [ + {file = "PyMySQL-1.1.0-py3-none-any.whl", hash = "sha256:8969ec6d763c856f7073c4c64662882675702efcb114b4bcbb955aea3a069fa7"}, + {file = "PyMySQL-1.1.0.tar.gz", hash = "sha256:4f13a7df8bf36a51e81dd9f3605fede45a4878fe02f9236349fd82a3f0612f96"}, +] + +[[package]] +name = "pyopenssl" +version = "23.3.0" +requires_python = ">=3.7" +summary = "Python wrapper module around the OpenSSL library" +groups = ["default"] +dependencies = [ + "cryptography<42,>=41.0.5", +] +files = [ + {file = "pyOpenSSL-23.3.0-py3-none-any.whl", hash = "sha256:6756834481d9ed5470f4a9393455154bc92fe7a64b7bc6ee2c804e78c52099b2"}, + {file = "pyOpenSSL-23.3.0.tar.gz", hash = "sha256:6b2cba5cc46e822750ec3e5a81ee12819850b11303630d575e98108a079c2b12"}, +] + +[[package]] +name = "pyparsing" +version = "3.1.1" +requires_python = ">=3.6.8" +summary = "pyparsing module - Classes and methods to define and execute parsing grammars" +groups = ["default"] +marker = "python_version > \"3.0\"" +files = [ + {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, + {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, +] + +[[package]] +name = "pypdfium2" +version = "4.27.0" +requires_python = ">= 3.6" +summary = "Python bindings to PDFium" +groups = ["default"] +files = [ + {file = "pypdfium2-4.27.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:2938f423c79b49df9057993f747e537a05b71bc2c847801ac743f27c3220d363"}, + {file = "pypdfium2-4.27.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f396941e070bf6c245890f2ffb2cb04f39585e3cda93ebb1648f1ed0e99b921f"}, + {file = "pypdfium2-4.27.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d593649fd787c4521f3b8e84892a070d62c19ae3dee7995f38e760e4e14c7c5"}, + {file = "pypdfium2-4.27.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:abb16df75dd0ba1c92553bbc9127edce46d59008047bb68abbf002963495d561"}, + {file = "pypdfium2-4.27.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69c76670e62db707fa5374eb8c71c2e9f9e4d6518707cd47725f7c2725129f8a"}, + {file = "pypdfium2-4.27.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fe503afef2a4c8180c75c1bb3c98eead4c60158b859c440c4c4bf4fa5b3ece"}, + {file = "pypdfium2-4.27.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:bfeb8337c1435ecaa584649b21b691152e06be3b01db761a2cd863fb2fdfda04"}, + {file = "pypdfium2-4.27.0-py3-none-musllinux_1_1_i686.whl", hash = "sha256:83c5c12714a5302b9947fe8fe97b003e9b934dec2529e5c10414d3ef5a3c8f19"}, + {file = "pypdfium2-4.27.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:c85e6f4fe5475665237da8a698e92c68339bdbc3257e2bcb325feacde5873dbc"}, + {file = "pypdfium2-4.27.0-py3-none-win32.whl", hash = "sha256:5c3413d4eeab8f2618b7af7d827dde5b7d40e752033c555e5889508b94f42090"}, + {file = "pypdfium2-4.27.0-py3-none-win_amd64.whl", hash = "sha256:597d262152e4aff36f6b2a395826c74c28977055b3b7233963cc91b243c74c78"}, + {file = "pypdfium2-4.27.0-py3-none-win_arm64.whl", hash = "sha256:ee4f4f433c9896953ef2ff8622a0912775b88380f91c6a2b8126fc5387d05620"}, + {file = "pypdfium2-4.27.0.tar.gz", hash = "sha256:1ff6ac30b98850558c0d163e37fdb868f683b1b2e8ae734072138571a0546222"}, +] + +[[package]] +name = "pyreadline3" +version = "3.4.1" +summary = "A python implementation of GNU readline." +groups = ["default"] +marker = "sys_platform == \"win32\" and python_version >= \"3.8\"" +files = [ + {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"}, + {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, +] + +[[package]] +name = "pytesseract" +version = "0.3.10" +requires_python = ">=3.7" +summary = "Python-tesseract is a python wrapper for Google's Tesseract-OCR" +groups = ["default"] +dependencies = [ + "Pillow>=8.0.0", + "packaging>=21.3", +] +files = [ + {file = "pytesseract-0.3.10-py3-none-any.whl", hash = "sha256:8f22cc98f765bf13517ead0c70effedb46c153540d25783e04014f28b55a5fc6"}, + {file = "pytesseract-0.3.10.tar.gz", hash = "sha256:f1c3a8b0f07fd01a1085d451f5b8315be6eec1d5577a6796d46dc7a62bd4120f"}, +] + +[[package]] +name = "pytest" +version = "8.0.1" +requires_python = ">=3.8" +summary = "pytest: simple powerful testing with Python" +groups = ["test"] +dependencies = [ + "colorama; sys_platform == \"win32\"", + "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", + "iniconfig", + "packaging", + "pluggy<2.0,>=1.3.0", + "tomli>=1.0.0; python_version < \"3.11\"", +] +files = [ + {file = "pytest-8.0.1-py3-none-any.whl", hash = "sha256:3e4f16fe1c0a9dc9d9389161c127c3edc5d810c38d6793042fb81d9f48a59fca"}, + {file = "pytest-8.0.1.tar.gz", hash = "sha256:267f6563751877d772019b13aacbe4e860d73fe8f651f28112e9ac37de7513ae"}, +] + +[[package]] +name = "python-crontab" +version = "3.0.0" +summary = "Python Crontab API" +groups = ["default"] +dependencies = [ + "python-dateutil", +] +files = [ + {file = "python-crontab-3.0.0.tar.gz", hash = "sha256:79fb7465039ddfd4fb93d072d6ee0d45c1ac8bf1597f0686ea14fd4361dba379"}, + {file = "python_crontab-3.0.0-py3-none-any.whl", hash = "sha256:6d5ba3c190ec76e4d252989a1644fcb233dbf53fbc8fceeb9febe1657b9fb1d4"}, +] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +summary = "Extensions to the standard Python datetime module" +groups = ["default"] +dependencies = [ + "six>=1.5", +] +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[[package]] +name = "python-dotenv" +version = "1.0.0" +requires_python = ">=3.8" +summary = "Read key-value pairs from a .env file and set them as environment variables" +groups = ["default"] +files = [ + {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, + {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, +] + +[[package]] +name = "python-engineio" +version = "4.9.0" +requires_python = ">=3.6" +summary = "Engine.IO server and client for Python" +groups = ["default"] +dependencies = [ + "simple-websocket>=0.10.0", +] +files = [ + {file = "python-engineio-4.9.0.tar.gz", hash = "sha256:e87459c15638e567711fd156e6f9c4a402668871bed79523f0ecfec744729ec7"}, + {file = "python_engineio-4.9.0-py3-none-any.whl", hash = "sha256:979859bff770725b75e60353d7ae53b397e8b517d05ba76733b404a3dcca3e4c"}, +] + +[[package]] +name = "python-magic" +version = "0.4.27" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +summary = "File type identification using libmagic" +groups = ["default"] +files = [ + {file = "python-magic-0.4.27.tar.gz", hash = "sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b"}, + {file = "python_magic-0.4.27-py2.py3-none-any.whl", hash = "sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3"}, +] + +[[package]] +name = "python-socketio" +version = "5.9.0" +requires_python = ">=3.6" +summary = "Socket.IO server and client for Python" +groups = ["default"] +dependencies = [ + "bidict>=0.21.0", + "python-engineio>=4.7.0", +] +files = [ + {file = "python-socketio-5.9.0.tar.gz", hash = "sha256:dc42735f65534187f381fde291ebf620216a4960001370f32de940229b2e7f8f"}, + {file = "python_socketio-5.9.0-py3-none-any.whl", hash = "sha256:c20f12e4ed0cba57581af26bbeea9998bc2eeebb3b952fa92493a1e051cfe9dc"}, +] + +[[package]] +name = "python3-openid" +version = "3.2.0" +summary = "OpenID support for modern servers and consumers." +groups = ["default"] +dependencies = [ + "defusedxml", +] +files = [ + {file = "python3-openid-3.2.0.tar.gz", hash = "sha256:33fbf6928f401e0b790151ed2b5290b02545e8775f982485205a066f874aaeaf"}, + {file = "python3_openid-3.2.0-py3-none-any.whl", hash = "sha256:6626f771e0417486701e0b4daff762e7212e820ca5b29fcc0d05f6f8736dfa6b"}, +] + +[[package]] +name = "pytz" +version = "2024.1" +summary = "World timezone definitions, modern and historical" +groups = ["default"] +files = [ + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, +] + +[[package]] +name = "pywin32" +version = "306" +summary = "Python for Window Extensions" +groups = ["default"] +marker = "sys_platform == \"win32\" or platform_system == \"Windows\"" +files = [ + {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, + {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, + {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, + {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, + {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, + {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, + {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +requires_python = ">=3.6" +summary = "YAML parser and emitter for Python" +groups = ["default"] +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-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 = "qdrant-client" +version = "1.7.0" +requires_python = ">=3.8,<3.13" +summary = "Client library for the Qdrant vector search engine" +groups = ["default"] +dependencies = [ + "grpcio-tools>=1.41.0", + "grpcio>=1.41.0", + "httpx[http2]>=0.14.0", + "numpy>=1.21; python_version >= \"3.8\" and python_version < \"3.12\"", + "portalocker<3.0.0,>=2.7.0", + "pydantic>=1.10.8", + "urllib3<2.0.0,>=1.26.14", +] +files = [ + {file = "qdrant_client-1.7.0-py3-none-any.whl", hash = "sha256:ab5779cf3f008da2a801c943413423f1ff434128dfaeda031f037453e1fa8306"}, + {file = "qdrant_client-1.7.0.tar.gz", hash = "sha256:bbe0656020c2f11061d7836b87e99ba6b50a028f5318459cc1fddf4ef73d9a8b"}, +] + +[[package]] +name = "realtime" +version = "1.0.2" +requires_python = ">=3.8,<4.0" +summary = "" +groups = ["default"] +dependencies = [ + "python-dateutil<3.0.0,>=2.8.1", + "typing-extensions<5.0.0,>=4.2.0", + "websockets<12.0,>=11.0", +] +files = [ + {file = "realtime-1.0.2-py3-none-any.whl", hash = "sha256:8f8375199fd917cd0ded818702321f91b208ab72794ade0a33cee9d55ae30f11"}, + {file = "realtime-1.0.2.tar.gz", hash = "sha256:776170a4329edc869b91e104c554cda02c8bf8e052cbb93c377e22482870959c"}, +] + +[[package]] +name = "redis" +version = "5.0.1" +requires_python = ">=3.7" +summary = "Python client for Redis database and key-value store" +groups = ["default"] +dependencies = [ + "async-timeout>=4.0.2; python_full_version <= \"3.11.2\"", +] +files = [ + {file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"}, + {file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"}, +] + +[[package]] +name = "referencing" +version = "0.33.0" +requires_python = ">=3.8" +summary = "JSON Referencing + Python" +groups = ["default"] +dependencies = [ + "attrs>=22.2.0", + "rpds-py>=0.7.0", +] +files = [ + {file = "referencing-0.33.0-py3-none-any.whl", hash = "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5"}, + {file = "referencing-0.33.0.tar.gz", hash = "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7"}, +] + +[[package]] +name = "regex" +version = "2023.12.25" +requires_python = ">=3.7" +summary = "Alternative regular expression module, to replace re." +groups = ["default"] +files = [ + {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0694219a1d54336fd0445ea382d49d36882415c0134ee1e8332afd1529f0baa5"}, + {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b014333bd0217ad3d54c143de9d4b9a3ca1c5a29a6d0d554952ea071cff0f1f8"}, + {file = "regex-2023.12.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d865984b3f71f6d0af64d0d88f5733521698f6c16f445bb09ce746c92c97c586"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e0eabac536b4cc7f57a5f3d095bfa557860ab912f25965e08fe1545e2ed8b4c"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c25a8ad70e716f96e13a637802813f65d8a6760ef48672aa3502f4c24ea8b400"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9b6d73353f777630626f403b0652055ebfe8ff142a44ec2cf18ae470395766e"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9cc99d6946d750eb75827cb53c4371b8b0fe89c733a94b1573c9dd16ea6c9e4"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88d1f7bef20c721359d8675f7d9f8e414ec5003d8f642fdfd8087777ff7f94b5"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cb3fe77aec8f1995611f966d0c656fdce398317f850d0e6e7aebdfe61f40e1cd"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7aa47c2e9ea33a4a2a05f40fcd3ea36d73853a2aae7b4feab6fc85f8bf2c9704"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:df26481f0c7a3f8739fecb3e81bc9da3fcfae34d6c094563b9d4670b047312e1"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c40281f7d70baf6e0db0c2f7472b31609f5bc2748fe7275ea65a0b4601d9b392"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:d94a1db462d5690ebf6ae86d11c5e420042b9898af5dcf278bd97d6bda065423"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ba1b30765a55acf15dce3f364e4928b80858fa8f979ad41f862358939bdd1f2f"}, + {file = "regex-2023.12.25-cp310-cp310-win32.whl", hash = "sha256:150c39f5b964e4d7dba46a7962a088fbc91f06e606f023ce57bb347a3b2d4630"}, + {file = "regex-2023.12.25-cp310-cp310-win_amd64.whl", hash = "sha256:09da66917262d9481c719599116c7dc0c321ffcec4b1f510c4f8a066f8768105"}, + {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1b9d811f72210fa9306aeb88385b8f8bcef0dfbf3873410413c00aa94c56c2b6"}, + {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d902a43085a308cef32c0d3aea962524b725403fd9373dea18110904003bac97"}, + {file = "regex-2023.12.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d166eafc19f4718df38887b2bbe1467a4f74a9830e8605089ea7a30dd4da8887"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7ad32824b7f02bb3c9f80306d405a1d9b7bb89362d68b3c5a9be53836caebdb"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:636ba0a77de609d6510235b7f0e77ec494d2657108f777e8765efc060094c98c"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fda75704357805eb953a3ee15a2b240694a9a514548cd49b3c5124b4e2ad01b"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f72cbae7f6b01591f90814250e636065850c5926751af02bb48da94dfced7baa"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db2a0b1857f18b11e3b0e54ddfefc96af46b0896fb678c85f63fb8c37518b3e7"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7502534e55c7c36c0978c91ba6f61703faf7ce733715ca48f499d3dbbd7657e0"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e8c7e08bb566de4faaf11984af13f6bcf6a08f327b13631d41d62592681d24fe"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:283fc8eed679758de38fe493b7d7d84a198b558942b03f017b1f94dda8efae80"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f44dd4d68697559d007462b0a3a1d9acd61d97072b71f6d1968daef26bc744bd"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:67d3ccfc590e5e7197750fcb3a2915b416a53e2de847a728cfa60141054123d4"}, + {file = "regex-2023.12.25-cp311-cp311-win32.whl", hash = "sha256:68191f80a9bad283432385961d9efe09d783bcd36ed35a60fb1ff3f1ec2efe87"}, + {file = "regex-2023.12.25-cp311-cp311-win_amd64.whl", hash = "sha256:7d2af3f6b8419661a0c421584cfe8aaec1c0e435ce7e47ee2a97e344b98f794f"}, + {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f7bc09bc9c29ebead055bcba136a67378f03d66bf359e87d0f7c759d6d4ffa31"}, + {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e14b73607d6231f3cc4622809c196b540a6a44e903bcfad940779c80dffa7be7"}, + {file = "regex-2023.12.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9eda5f7a50141291beda3edd00abc2d4a5b16c29c92daf8d5bd76934150f3edc"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc6bb9aa69aacf0f6032c307da718f61a40cf970849e471254e0e91c56ffca95"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:298dc6354d414bc921581be85695d18912bea163a8b23cac9a2562bbcd5088b1"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f4e475a80ecbd15896a976aa0b386c5525d0ed34d5c600b6d3ebac0a67c7ddf"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531ac6cf22b53e0696f8e1d56ce2396311254eb806111ddd3922c9d937151dae"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22f3470f7524b6da61e2020672df2f3063676aff444db1daa283c2ea4ed259d6"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:89723d2112697feaa320c9d351e5f5e7b841e83f8b143dba8e2d2b5f04e10923"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0ecf44ddf9171cd7566ef1768047f6e66975788258b1c6c6ca78098b95cf9a3d"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:905466ad1702ed4acfd67a902af50b8db1feeb9781436372261808df7a2a7bca"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:4558410b7a5607a645e9804a3e9dd509af12fb72b9825b13791a37cd417d73a5"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7e316026cc1095f2a3e8cc012822c99f413b702eaa2ca5408a513609488cb62f"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3b1de218d5375cd6ac4b5493e0b9f3df2be331e86520f23382f216c137913d20"}, + {file = "regex-2023.12.25-cp39-cp39-win32.whl", hash = "sha256:11a963f8e25ab5c61348d090bf1b07f1953929c13bd2309a0662e9ff680763c9"}, + {file = "regex-2023.12.25-cp39-cp39-win_amd64.whl", hash = "sha256:e693e233ac92ba83a87024e1d32b5f9ab15ca55ddd916d878146f4e3406b5c91"}, + {file = "regex-2023.12.25.tar.gz", hash = "sha256:29171aa128da69afdf4bde412d5bedc335f2ca8fcfe4489038577d05f16181e5"}, +] + +[[package]] +name = "replicate" +version = "0.22.0" +requires_python = ">=3.8" +summary = "Python client for Replicate" +groups = ["default"] +dependencies = [ + "httpx<1,>=0.21.0", + "packaging", + "pydantic>1", + "typing-extensions>=4.5.0", +] +files = [ + {file = "replicate-0.22.0-py3-none-any.whl", hash = "sha256:a11e20e9589981a96bee6f3817494b5cc29735a108c71aff4515a81863ad9996"}, + {file = "replicate-0.22.0.tar.gz", hash = "sha256:cab48c15ede619d5aa7d023a241626d504c70ea2b7db5792ebfb5ae9fa373cbc"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +requires_python = ">=3.7" +summary = "Python HTTP for Humans." +groups = ["default"] +dependencies = [ + "certifi>=2017.4.17", + "charset-normalizer<4,>=2", + "idna<4,>=2.5", + "urllib3<3,>=1.21.1", +] +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[[package]] +name = "requests-oauthlib" +version = "1.3.1" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +summary = "OAuthlib authentication support for Requests." +groups = ["default"] +dependencies = [ + "oauthlib>=3.0.0", + "requests>=2.0.0", +] +files = [ + {file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"}, + {file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"}, +] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +summary = "A utility belt for advanced users of python-requests" +groups = ["default"] +dependencies = [ + "requests<3.0.0,>=2.0.1", +] +files = [ + {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, + {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, +] + +[[package]] +name = "rich" +version = "13.7.0" +requires_python = ">=3.7.0" +summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +groups = ["default"] +dependencies = [ + "markdown-it-py>=2.2.0", + "pygments<3.0.0,>=2.13.0", +] +files = [ + {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, + {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, +] + +[[package]] +name = "rpds-py" +version = "0.18.0" +requires_python = ">=3.8" +summary = "Python bindings to Rust's persistent data structures (rpds)" +groups = ["default"] +files = [ + {file = "rpds_py-0.18.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e"}, + {file = "rpds_py-0.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434"}, + {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3"}, + {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e"}, + {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88"}, + {file = "rpds_py-0.18.0-cp310-none-win32.whl", hash = "sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337"}, + {file = "rpds_py-0.18.0-cp310-none-win_amd64.whl", hash = "sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66"}, + {file = "rpds_py-0.18.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4"}, + {file = "rpds_py-0.18.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6"}, + {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688"}, + {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b"}, + {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836"}, + {file = "rpds_py-0.18.0-cp311-none-win32.whl", hash = "sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1"}, + {file = "rpds_py-0.18.0-cp311-none-win_amd64.whl", hash = "sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa"}, + {file = "rpds_py-0.18.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33"}, + {file = "rpds_py-0.18.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f"}, + {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e"}, + {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024"}, + {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20"}, + {file = "rpds_py-0.18.0-cp39-none-win32.whl", hash = "sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7"}, + {file = "rpds_py-0.18.0-cp39-none-win_amd64.whl", hash = "sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f"}, + {file = "rpds_py-0.18.0.tar.gz", hash = "sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d"}, +] + +[[package]] +name = "rsa" +version = "4.9" +requires_python = ">=3.6,<4" +summary = "Pure-Python RSA implementation" +groups = ["default"] +dependencies = [ + "pyasn1>=0.1.3", +] +files = [ + {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, + {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, +] + +[[package]] +name = "s3fs" +version = "2023.6.0" +requires_python = ">= 3.8" +summary = "Convenient Filesystem interface over S3" +groups = ["default"] +dependencies = [ + "aiobotocore~=2.5.0", + "aiohttp!=4.0.0a0,!=4.0.0a1", + "fsspec==2023.6.0", +] +files = [ + {file = "s3fs-2023.6.0-py3-none-any.whl", hash = "sha256:d1a0a423d0d2e17fb2a193d9531935dc3f45ba742693448a461b6b34f6a92a24"}, + {file = "s3fs-2023.6.0.tar.gz", hash = "sha256:63fd8ddf05eb722de784b7b503196107f2a518061298cf005a8a4715b4d49117"}, +] + +[[package]] +name = "s3fs" +version = "2023.6.0" +extras = ["boto3"] +requires_python = ">= 3.8" +summary = "Convenient Filesystem interface over S3" +groups = ["default"] +dependencies = [ + "aiobotocore[boto3]~=2.5.0", + "s3fs==2023.6.0", +] +files = [ + {file = "s3fs-2023.6.0-py3-none-any.whl", hash = "sha256:d1a0a423d0d2e17fb2a193d9531935dc3f45ba742693448a461b6b34f6a92a24"}, + {file = "s3fs-2023.6.0.tar.gz", hash = "sha256:63fd8ddf05eb722de784b7b503196107f2a518061298cf005a8a4715b4d49117"}, +] + +[[package]] +name = "s3transfer" +version = "0.6.2" +requires_python = ">= 3.7" +summary = "An Amazon S3 Transfer Manager" +groups = ["default"] +dependencies = [ + "botocore<2.0a.0,>=1.12.36", +] +files = [ + {file = "s3transfer-0.6.2-py3-none-any.whl", hash = "sha256:b014be3a8a2aab98cfe1abc7229cc5a9a0cf05eb9c1f2b86b230fd8df3f78084"}, + {file = "s3transfer-0.6.2.tar.gz", hash = "sha256:cab66d3380cca3e70939ef2255d01cd8aece6a4907a9528740f668c4b0611861"}, +] + +[[package]] +name = "safetensors" +version = "0.4.2" +requires_python = ">=3.7" +summary = "" +groups = ["default"] +files = [ + {file = "safetensors-0.4.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:69d8bb8384dc2cb5b72c36c4d6980771b293d1a1377b378763f5e37b6bb8d133"}, + {file = "safetensors-0.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3d420e19fcef96d0067f4de4699682b4bbd85fc8fea0bd45fcd961fdf3e8c82c"}, + {file = "safetensors-0.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ca54742122fa3c4821754adb67318e1cd25c3a22bbf0c5520d5176e77a099ac"}, + {file = "safetensors-0.4.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b47aa643afdfd66cf7ce4c184092ae734e15d10aba2c2948f24270211801c3c"}, + {file = "safetensors-0.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d88a16bbc330f27e7f2d4caaf6fb061ad0b8a756ecc4033260b0378e128ce8a2"}, + {file = "safetensors-0.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9223b8ac21085db614a510eb3445e7083cae915a9202357555fa939695d4f57"}, + {file = "safetensors-0.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce6cb86133dc8930a7ab5e7438545a7f205f7a1cdd5aaf108c1d0da6bdcfbc2b"}, + {file = "safetensors-0.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b8a628e0ae2bbc334b62952c384aa5f41621d01850f8d67b04a96b9c39dd7326"}, + {file = "safetensors-0.4.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:88d6beb7f811a081e0e5f1d9669fdac816c45340c04b1eaf7ebfda0ce93ea403"}, + {file = "safetensors-0.4.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b57fc5b1b54cb12d8690a58a4cf4b7144730d4bde9d98aa0e1dab6295a1cd579"}, + {file = "safetensors-0.4.2-cp310-none-win32.whl", hash = "sha256:9d87a1c98803c16cf113b9ba03f07b2dce5e8eabfd1811a7f7323fcaa2a1bf47"}, + {file = "safetensors-0.4.2-cp310-none-win_amd64.whl", hash = "sha256:18930ec1d1ecb526d3d9835abc2489b8f1530877518f0c541e77ef0b7abcbd99"}, + {file = "safetensors-0.4.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c5dd2ed788730ed56b415d1a11c62026b8cc8c573f55a2092afb3ab383e94fff"}, + {file = "safetensors-0.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc41791b33efb9c83a59b731619f3d15f543dfe71f3a793cb8fbf9bd5d0d5d71"}, + {file = "safetensors-0.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c888bf71d5ca12a720f1ed87d407c4918afa022fb247a6546d8fac15b1f112b"}, + {file = "safetensors-0.4.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e6b2feb4b47226a16a792e6fac3f49442714884a3d4c1008569d5068a3941be9"}, + {file = "safetensors-0.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f41cc0ee4b838ae8f4d8364a1b162067693d11a3893f0863be8c228d40e4d0ee"}, + {file = "safetensors-0.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:51b7228e46c0a483c40ba4b9470dea00fb1ff8685026bb4766799000f6328ac2"}, + {file = "safetensors-0.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02697f8f2be8ca3c37a4958702dbdb1864447ef765e18b5328a1617022dcf164"}, + {file = "safetensors-0.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:27fd8f65cf7c80e4280cae1ee6bcd85c483882f6580821abe71ee1a0d3dcfca7"}, + {file = "safetensors-0.4.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c487b5f113b0924c9534a07dc034830fb4ef05ce9bb6d78cfe016a7dedfe281f"}, + {file = "safetensors-0.4.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:da7f6483f3fe67ff39b3a55552552c67930ea10a36e9f2539d36fc205273d767"}, + {file = "safetensors-0.4.2-cp311-none-win32.whl", hash = "sha256:52a7012f6cb9cb4a132760b6308daede18a9f5f8952ce08adc7c67a7d865c2d8"}, + {file = "safetensors-0.4.2-cp311-none-win_amd64.whl", hash = "sha256:4d1361a097ac430b310ce9eed8ed4746edee33ddafdfbb965debc8966fc34dc2"}, + {file = "safetensors-0.4.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a5a921b4fe6925f9942adff3ebae8c16e0487908c54586a5a42f35b59fd69794"}, + {file = "safetensors-0.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b691727228c28f2d82d8a92b2bc26e7a1f129ee40b2f2a3185b5974e038ed47c"}, + {file = "safetensors-0.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91ca1056decc4e981248786e87b2a202d4841ee5f99d433f1adf3d44d4bcfa0e"}, + {file = "safetensors-0.4.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:55969fd2e6fdb38dc221b0ab380668c21b0efa12a7562db9924759faa3c51757"}, + {file = "safetensors-0.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ae429bfaecc10ab5fe78c93009b3d1656c1581da560041e700eadb497dbe7a4"}, + {file = "safetensors-0.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff88f194fe4ac50b463a4a6f0c03af9ad72eb5d24ec6d6730af59522e37fedb"}, + {file = "safetensors-0.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a80cb48d0a447f8dd18e61813efa7d3f8f8d52edf0f05806abc0c59b83431f57"}, + {file = "safetensors-0.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b286fb7adfee70a4189898ac2342b8a67d5f493e6b21b0af89ca8eac1b967cbf"}, + {file = "safetensors-0.4.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0ceeff9ddbab4f78738489eb6682867ae946178776f33699737b2129b5394dc1"}, + {file = "safetensors-0.4.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a26fae748a7488cb3aac381eddfa818c42052c87b5e689fb4c6e82ed58cec209"}, + {file = "safetensors-0.4.2-cp39-none-win32.whl", hash = "sha256:039a42ab33c9d68b39706fd38f1922ace26866eff246bf20271edb619f5f848b"}, + {file = "safetensors-0.4.2-cp39-none-win_amd64.whl", hash = "sha256:b3a3e1f5b85859e398773f064943b62a4059f225008a2a8ee6add1edcf77cacf"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:4e70d442ad17e8b153ef9095bf48ea64f15a66bf26dc2b6ca94660c154edbc24"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b90f1d9809caf4ff395951b4703295a68d12907f6945bbc3129e934ff8ae46f6"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c7ac9ad3728838006598e296b3ae9f27d80b489effd4685b92d97b3fc4c98f6"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5730d77e6ff7f4c7039e20913661ad0ea2f86c09e71c039e73dfdd1f394f08"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:44feb8cb156d6803dcd19fc6b81b27235f29b877660605a6ac35e1da7d64f0e4"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:523a241c33e7c827ab9a3a23760d75c7d062f43dfe55b6b019409f89b0fb52d1"}, + {file = "safetensors-0.4.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fb18300e8eb74291225214f26c9a8ae2110fd61a6c9b5a2ff4c4e0eb1bb9a998"}, + {file = "safetensors-0.4.2-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fe5437ff9fb116e44f2ab558981249ae63f978392b4576e62fcfe167d353edbc"}, + {file = "safetensors-0.4.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9304a0934ced5a5d272f39de36291dc141dfc152d277f03fb4d65f2fb2ffa7c"}, + {file = "safetensors-0.4.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:160ba1b1e11cf874602c233ab80a14f588571d09556cbc3586900121d622b5ed"}, + {file = "safetensors-0.4.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04fcd6fcf7d9c13c7e5dc7e08de5e492ee4daa8f4ad74b4d8299d3eb0224292f"}, + {file = "safetensors-0.4.2-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:906d14c4a677d35834fb0f3a5455ef8305e1bba10a5e0f2e0f357b3d1ad989f2"}, + {file = "safetensors-0.4.2-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:df3fcdec0cd543084610d1f09c65cdb10fb3079f79bceddc092b0d187c6a265b"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5ca76f13fb1cef242ea3ad2cb37388e7d005994f42af8b44bee56ba48b2d45ce"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:278a1a3414c020785decdcd741c578725721274d2f9f787fcc930882e83b89cc"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b5a461cc68ecd42d9d546e5e1268a39d8ede7934a68d1ce17c3c659cb829d6"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2341411412a41671d25e26bed59ec121e46bf4fadb8132895e610411c4b9681"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3497ac3895acf17c5f98197f1fa4769f09c5e7ede07fcb102f1c201e663e052c"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:01b5e71d3754d2201294f1eb7a6d59cce3a5702ff96d83d226571b2ca2183837"}, + {file = "safetensors-0.4.2-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3627dbd1ea488dd8046a0491de5087f3c0d641e7acc80c0189a33c69398f1cd1"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9d56f0ef53afad26ec54ceede78a43e9a23a076dadbbda7b44d304c591abf4c1"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b259ca73d42daf658a1bda463f1f83885ae4d93a60869be80d7f7dfcc9d8bbb5"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ebc3cd401e4eb54e7c0a70346be565e81942d9a41fafd5f4bf7ab3a55d10378"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5bc384a0309b706aa0425c93abb0390508a61bf029ce99c7d9df4220f25871a5"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:af2d8f7235d8a08fbccfb8394387890e7fa38942b349a94e6eff13c52ac98087"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0911315bbcc5289087d063c2c2c7ccd711ea97a7e557a7bce005ac2cf80146aa"}, + {file = "safetensors-0.4.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1efe31673be91832d73439a2af426743e1395fc9ef7b081914e9e1d567bd7b5f"}, + {file = "safetensors-0.4.2.tar.gz", hash = "sha256:acc85dcb09ec5e8aa787f588d7ad4d55c103f31e4ff060e17d92cc0e8b8cac73"}, +] + +[[package]] +name = "setuptools" +version = "69.1.1" +requires_python = ">=3.8" +summary = "Easily download, build, install, upgrade, and uninstall Python packages" +groups = ["default"] +files = [ + {file = "setuptools-69.1.1-py3-none-any.whl", hash = "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56"}, + {file = "setuptools-69.1.1.tar.gz", hash = "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8"}, +] + +[[package]] +name = "shapely" +version = "2.0.3" +requires_python = ">=3.7" +summary = "Manipulation and analysis of geometric objects" +groups = ["default"] +dependencies = [ + "numpy<2,>=1.14", +] +files = [ + {file = "shapely-2.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:af7e9abe180b189431b0f490638281b43b84a33a960620e6b2e8d3e3458b61a1"}, + {file = "shapely-2.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:98040462b36ced9671e266b95c326b97f41290d9d17504a1ee4dc313a7667b9c"}, + {file = "shapely-2.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:71eb736ef2843f23473c6e37f6180f90f0a35d740ab284321548edf4e55d9a52"}, + {file = "shapely-2.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:881eb9dbbb4a6419667e91fcb20313bfc1e67f53dbb392c6840ff04793571ed1"}, + {file = "shapely-2.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f10d2ccf0554fc0e39fad5886c839e47e207f99fdf09547bc687a2330efda35b"}, + {file = "shapely-2.0.3-cp310-cp310-win32.whl", hash = "sha256:6dfdc077a6fcaf74d3eab23a1ace5abc50c8bce56ac7747d25eab582c5a2990e"}, + {file = "shapely-2.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:64c5013dacd2d81b3bb12672098a0b2795c1bf8190cfc2980e380f5ef9d9e4d9"}, + {file = "shapely-2.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:56cee3e4e8159d6f2ce32e421445b8e23154fd02a0ac271d6a6c0b266a8e3cce"}, + {file = "shapely-2.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:619232c8276fded09527d2a9fd91a7885ff95c0ff9ecd5e3cb1e34fbb676e2ae"}, + {file = "shapely-2.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2a7d256db6f5b4b407dc0c98dd1b2fcf1c9c5814af9416e5498d0a2e4307a4b"}, + {file = "shapely-2.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45f0c8cd4583647db3216d965d49363e6548c300c23fd7e57ce17a03f824034"}, + {file = "shapely-2.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13cb37d3826972a82748a450328fe02a931dcaed10e69a4d83cc20ba021bc85f"}, + {file = "shapely-2.0.3-cp311-cp311-win32.whl", hash = "sha256:9302d7011e3e376d25acd30d2d9e70d315d93f03cc748784af19b00988fc30b1"}, + {file = "shapely-2.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:6b464f2666b13902835f201f50e835f2f153f37741db88f68c7f3b932d3505fa"}, + {file = "shapely-2.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:083d026e97b6c1f4a9bd2a9171c7692461092ed5375218170d91705550eecfd5"}, + {file = "shapely-2.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:27b6e1910094d93e9627f2664121e0e35613262fc037051680a08270f6058daf"}, + {file = "shapely-2.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:71b2de56a9e8c0e5920ae5ddb23b923490557ac50cb0b7fa752761bf4851acde"}, + {file = "shapely-2.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d279e56bbb68d218d63f3efc80c819cedcceef0e64efbf058a1df89dc57201b"}, + {file = "shapely-2.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88566d01a30f0453f7d038db46bc83ce125e38e47c5f6bfd4c9c287010e9bf74"}, + {file = "shapely-2.0.3-cp39-cp39-win32.whl", hash = "sha256:58afbba12c42c6ed44c4270bc0e22f3dadff5656d711b0ad335c315e02d04707"}, + {file = "shapely-2.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:5026b30433a70911979d390009261b8c4021ff87c7c3cbd825e62bb2ffa181bc"}, + {file = "shapely-2.0.3.tar.gz", hash = "sha256:4d65d0aa7910af71efa72fd6447e02a8e5dd44da81a983de9d736d6e6ccbe674"}, +] + +[[package]] +name = "simple-websocket" +version = "1.0.0" +requires_python = ">=3.6" +summary = "Simple WebSocket server and client for Python" +groups = ["default"] +dependencies = [ + "wsproto", +] +files = [ + {file = "simple-websocket-1.0.0.tar.gz", hash = "sha256:17d2c72f4a2bd85174a97e3e4c88b01c40c3f81b7b648b0cc3ce1305968928c8"}, + {file = "simple_websocket-1.0.0-py3-none-any.whl", hash = "sha256:1d5bf585e415eaa2083e2bcf02a3ecf91f9712e7b3e6b9fa0b461ad04e0837bc"}, +] + +[[package]] +name = "six" +version = "1.16.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +summary = "Python 2 and 3 compatibility utilities" +groups = ["default"] +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 = "smart-open" +version = "6.4.0" +requires_python = ">=3.6,<4.0" +summary = "Utils for streaming large files (S3, HDFS, GCS, Azure Blob Storage, gzip, bz2...)" +groups = ["default"] +files = [ + {file = "smart_open-6.4.0-py3-none-any.whl", hash = "sha256:8d3ef7e6997e8e42dd55c74166ed21e6ac70664caa32dd940b26d54a8f6b4142"}, + {file = "smart_open-6.4.0.tar.gz", hash = "sha256:be3c92c246fbe80ebce8fbacb180494a481a77fcdcb7c1aadb2ea5b9c2bee8b9"}, +] + +[[package]] +name = "smmap" +version = "5.0.1" +requires_python = ">=3.7" +summary = "A pure Python implementation of a sliding window memory map manager" +groups = ["default"] +files = [ + {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, + {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, +] + +[[package]] +name = "sniffio" +version = "1.3.0" +requires_python = ">=3.7" +summary = "Sniff out which async library your code is running under" +groups = ["default"] +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + +[[package]] +name = "snowflake-connector-python" +version = "3.6.0" +requires_python = ">=3.8" +summary = "Snowflake Connector for Python" +groups = ["default"] +dependencies = [ + "asn1crypto<2.0.0,>0.24.0", + "certifi>=2017.4.17", + "cffi<2.0.0,>=1.9", + "charset-normalizer<4,>=2", + "cryptography<42.0.0,>=3.1.0", + "filelock<4,>=3.5", + "idna<4,>=2.5", + "packaging", + "platformdirs<4.0.0,>=2.6.0", + "pyOpenSSL<24.0.0,>=16.2.0", + "pyjwt<3.0.0", + "pytz", + "requests<3.0.0", + "sortedcontainers>=2.4.0", + "tomlkit", + "typing-extensions<5,>=4.3", + "urllib3<2.0.0,>=1.21.1; python_version < \"3.10\"", +] +files = [ + {file = "snowflake-connector-python-3.6.0.tar.gz", hash = "sha256:15667a918780d79da755e6a60bbf6918051854951e8f56ccdf5692283e9a8479"}, + {file = "snowflake_connector_python-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4093b38cf9abf95c38119f0b23b07e23dc7a8689b956cd5d34975e1875741f20"}, + {file = "snowflake_connector_python-3.6.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:cf5a964fe01b177063f8c44d14df3a72715580bcd195788ec2822090f37330a5"}, + {file = "snowflake_connector_python-3.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55a6418cec585b050e6f05404f25e62b075a3bbea587dc1f903de15640565c58"}, + {file = "snowflake_connector_python-3.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7c76aea92b87f6ecd604e9c934aac8a779f2e20f3be1d990d53bb5b6d87b009"}, + {file = "snowflake_connector_python-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:9dfcf178271e892e64e4092b9e011239a066ce5de848afd2efe3f13197a9f8b3"}, + {file = "snowflake_connector_python-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4916f9b4a0efd7c96d1fa50a157e05907b6935f91492cca7f200b43cc178a25e"}, + {file = "snowflake_connector_python-3.6.0-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:f15024c66db5e87d359216ec733a2974d7562aa38f3f18c8b6e65489839e00d7"}, + {file = "snowflake_connector_python-3.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcbd3102f807ebbbae52b1b5683d45cd7b3dcb0eaec131233ba6b156e8d70fa4"}, + {file = "snowflake_connector_python-3.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7662e2de25b885abe08ab866cf7c7b026ad1af9faa39c25e2c25015ef807abe3"}, + {file = "snowflake_connector_python-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:d1fa102f55ee166cc766aeee3f9333b17b4bede6fb088eee1e1f022df15b6d81"}, + {file = "snowflake_connector_python-3.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bf8c1ad5aab5304fefa2a4178061a24c96da45e3e3db9d901621e9953e005402"}, + {file = "snowflake_connector_python-3.6.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1058ab5c98cc62fde8b3f021f0a5076cb7865b5cdab8a9bccde0df88b9e91334"}, + {file = "snowflake_connector_python-3.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b93f55989f80d69278e0f40a7a1c0e737806b7c0ddb0351513a752b837243e8"}, + {file = "snowflake_connector_python-3.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50dd954ea5918d3242ded69225b72f701963cd9c043ee7d9ab35dc22211611c8"}, + {file = "snowflake_connector_python-3.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:4ad42613b87f31441d07a8ea242f4c28ed5eb7b6e05986f9e94a7e44b96d3d1e"}, +] + +[[package]] +name = "snowflake-connector-python" +version = "3.6.0" +extras = ["pandas"] +requires_python = ">=3.8" +summary = "Snowflake Connector for Python" +groups = ["default"] +dependencies = [ + "pandas<2.2.0,>=1.0.0", + "pyarrow", + "snowflake-connector-python==3.6.0", +] +files = [ + {file = "snowflake-connector-python-3.6.0.tar.gz", hash = "sha256:15667a918780d79da755e6a60bbf6918051854951e8f56ccdf5692283e9a8479"}, + {file = "snowflake_connector_python-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4093b38cf9abf95c38119f0b23b07e23dc7a8689b956cd5d34975e1875741f20"}, + {file = "snowflake_connector_python-3.6.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:cf5a964fe01b177063f8c44d14df3a72715580bcd195788ec2822090f37330a5"}, + {file = "snowflake_connector_python-3.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55a6418cec585b050e6f05404f25e62b075a3bbea587dc1f903de15640565c58"}, + {file = "snowflake_connector_python-3.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7c76aea92b87f6ecd604e9c934aac8a779f2e20f3be1d990d53bb5b6d87b009"}, + {file = "snowflake_connector_python-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:9dfcf178271e892e64e4092b9e011239a066ce5de848afd2efe3f13197a9f8b3"}, + {file = "snowflake_connector_python-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4916f9b4a0efd7c96d1fa50a157e05907b6935f91492cca7f200b43cc178a25e"}, + {file = "snowflake_connector_python-3.6.0-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:f15024c66db5e87d359216ec733a2974d7562aa38f3f18c8b6e65489839e00d7"}, + {file = "snowflake_connector_python-3.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcbd3102f807ebbbae52b1b5683d45cd7b3dcb0eaec131233ba6b156e8d70fa4"}, + {file = "snowflake_connector_python-3.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7662e2de25b885abe08ab866cf7c7b026ad1af9faa39c25e2c25015ef807abe3"}, + {file = "snowflake_connector_python-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:d1fa102f55ee166cc766aeee3f9333b17b4bede6fb088eee1e1f022df15b6d81"}, + {file = "snowflake_connector_python-3.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bf8c1ad5aab5304fefa2a4178061a24c96da45e3e3db9d901621e9953e005402"}, + {file = "snowflake_connector_python-3.6.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1058ab5c98cc62fde8b3f021f0a5076cb7865b5cdab8a9bccde0df88b9e91334"}, + {file = "snowflake_connector_python-3.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b93f55989f80d69278e0f40a7a1c0e737806b7c0ddb0351513a752b837243e8"}, + {file = "snowflake_connector_python-3.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50dd954ea5918d3242ded69225b72f701963cd9c043ee7d9ab35dc22211611c8"}, + {file = "snowflake_connector_python-3.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:4ad42613b87f31441d07a8ea242f4c28ed5eb7b6e05986f9e94a7e44b96d3d1e"}, +] + +[[package]] +name = "social-auth-app-django" +version = "5.3.0" +requires_python = ">=3.7" +summary = "Python Social Authentication, Django integration." +groups = ["default"] +dependencies = [ + "Django>=3.2", + "social-auth-core>=4.4.1", +] +files = [ + {file = "social-auth-app-django-5.3.0.tar.gz", hash = "sha256:8719d57d01d80dcc9629a46e6806889aa9714fe4b658d2ebe3c120450591031d"}, + {file = "social_auth_app_django-5.3.0-py3-none-any.whl", hash = "sha256:2e71234656ddebe0c5b5ad450d42ee49f52a3f2d1708687fccf2a2c92d31a624"}, +] + +[[package]] +name = "social-auth-core" +version = "4.4.2" +requires_python = ">=3.6" +summary = "Python social authentication made simple." +groups = ["default"] +dependencies = [ + "PyJWT>=2.0.0", + "cryptography>=1.4", + "defusedxml>=0.5.0rc1", + "oauthlib>=1.0.3", + "python3-openid>=3.0.10", + "requests-oauthlib>=0.6.1", + "requests>=2.9.1", +] +files = [ + {file = "social-auth-core-4.4.2.tar.gz", hash = "sha256:9791d7c7aee2ac8517fe7a2ea2f942a8a5492b3a4ccb44a9b0dacc87d182f2aa"}, + {file = "social_auth_core-4.4.2-py3-none-any.whl", hash = "sha256:ea7a19c46b791b767e95f467881b53c5fd0d1efb40048d9ed3dbc46daa05c954"}, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +summary = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +groups = ["default"] +files = [ + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, +] + +[[package]] +name = "soupsieve" +version = "2.5" +requires_python = ">=3.8" +summary = "A modern CSS selector implementation for Beautiful Soup." +groups = ["default"] +files = [ + {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, + {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, +] + +[[package]] +name = "spinners" +version = "0.0.24" +summary = "Spinners for terminals" +groups = ["default"] +files = [ + {file = "spinners-0.0.24-py3-none-any.whl", hash = "sha256:2fa30d0b72c9650ad12bbe031c9943b8d441e41b4f5602b0ec977a19f3290e98"}, + {file = "spinners-0.0.24.tar.gz", hash = "sha256:1eb6aeb4781d72ab42ed8a01dcf20f3002bf50740d7154d12fb8c9769bf9e27f"}, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.26" +requires_python = ">=3.7" +summary = "Database Abstraction Library" +groups = ["default"] +dependencies = [ + "greenlet!=0.4.17; platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\"", + "typing-extensions>=4.6.0", +] +files = [ + {file = "SQLAlchemy-2.0.26-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:56524d767713054f8758217b3a811f6a736e0ae34e7afc33b594926589aa9609"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c2d8a2c68b279617f13088bdc0fc0e9b5126f8017f8882ff08ee41909fab0713"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84d377645913d47f0dc802b415bcfe7fb085d86646a12278d77c12eb75b5e1b4"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fc0628d2026926404dabc903dc5628f7d936a792aa3a1fc54a20182df8e2172"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:872f2907ade52601a1e729e85d16913c24dc1f6e7c57d11739f18dcfafde29db"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ba46fa770578b3cf3b5b77dadb7e94fda7692dd4d1989268ef3dcb65f31c40a3"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-win32.whl", hash = "sha256:651d10fdba7984bf100222d6e4acc496fec46493262b6170be1981ef860c6184"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-win_amd64.whl", hash = "sha256:8f95ede696ab0d7328862d69f29b643d35b668c4f3619cb2f0281adc16e64c1b"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fab1bb909bd24accf2024a69edd4f885ded182c079c4dbcd515b4842f86b07cb"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7ee16afd083bb6bb5ab3962ac7f0eafd1d196c6399388af35fef3d1c6d6d9bb"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:379af901ceb524cbee5e15c1713bf9fd71dc28053286b7917525d01b938b9628"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94a78f56ea13f4d6e9efcd2a2d08cc13531918e0516563f6303c4ad98c81e21d"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a481cc2eec83776ff7b6bb12c8e85d0378af0e2ec4584ac3309365a2a380c64b"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8cbeb0e49b605cd75f825fb9239a554803ef2bef1a7b2a8b428926ed518b6b63"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-win32.whl", hash = "sha256:e70cce65239089390c193a7b0d171ce89d2e3dedf797f8010031b2aa2b1e9c80"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-win_amd64.whl", hash = "sha256:750d1ef39d50520527c45c309c3cb10bbfa6131f93081b4e93858abb5ece2501"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4f57af0866f6629eae2d24d022ba1a4c1bac9b16d45027bbfcda4c9d5b0d8f26"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e1a532bc33163fb19c4759a36504a23e63032bc8d47cee1c66b0b70a04a0957b"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02a4f954ccb17bd8cff56662efc806c5301508233dc38d0253a5fdb2f33ca3ba"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a678f728fb075e74aaa7fdc27f8af8f03f82d02e7419362cc8c2a605c16a4114"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8b39462c9588d4780f041e1b84d2ba038ac01c441c961bbee622dd8f53dec69f"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98f4d0d2bda2921af5b0c2ca99207cdab00f2922da46a6336c62c8d6814303a7"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-win32.whl", hash = "sha256:6d68e6b507a3dd20c0add86ac0a0ca061d43c9a0162a122baa5fe952f14240f1"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-win_amd64.whl", hash = "sha256:fb97a9b93b953084692a52a7877957b7a88dfcedc0c5652124f5aebf5999f7fe"}, + {file = "SQLAlchemy-2.0.26-py3-none-any.whl", hash = "sha256:1128b2cdf49107659f6d1f452695f43a20694cc9305a86e97b70793a1c74eeb4"}, + {file = "SQLAlchemy-2.0.26.tar.gz", hash = "sha256:e1bcd8fcb30305e27355d553608c2c229d3e589fb7ff406da7d7e5d50fa14d0d"}, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.26" +extras = ["asyncio"] +requires_python = ">=3.7" +summary = "Database Abstraction Library" +groups = ["default"] +dependencies = [ + "SQLAlchemy==2.0.26", + "greenlet!=0.4.17", +] +files = [ + {file = "SQLAlchemy-2.0.26-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:56524d767713054f8758217b3a811f6a736e0ae34e7afc33b594926589aa9609"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c2d8a2c68b279617f13088bdc0fc0e9b5126f8017f8882ff08ee41909fab0713"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84d377645913d47f0dc802b415bcfe7fb085d86646a12278d77c12eb75b5e1b4"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fc0628d2026926404dabc903dc5628f7d936a792aa3a1fc54a20182df8e2172"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:872f2907ade52601a1e729e85d16913c24dc1f6e7c57d11739f18dcfafde29db"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ba46fa770578b3cf3b5b77dadb7e94fda7692dd4d1989268ef3dcb65f31c40a3"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-win32.whl", hash = "sha256:651d10fdba7984bf100222d6e4acc496fec46493262b6170be1981ef860c6184"}, + {file = "SQLAlchemy-2.0.26-cp310-cp310-win_amd64.whl", hash = "sha256:8f95ede696ab0d7328862d69f29b643d35b668c4f3619cb2f0281adc16e64c1b"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fab1bb909bd24accf2024a69edd4f885ded182c079c4dbcd515b4842f86b07cb"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7ee16afd083bb6bb5ab3962ac7f0eafd1d196c6399388af35fef3d1c6d6d9bb"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:379af901ceb524cbee5e15c1713bf9fd71dc28053286b7917525d01b938b9628"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94a78f56ea13f4d6e9efcd2a2d08cc13531918e0516563f6303c4ad98c81e21d"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a481cc2eec83776ff7b6bb12c8e85d0378af0e2ec4584ac3309365a2a380c64b"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8cbeb0e49b605cd75f825fb9239a554803ef2bef1a7b2a8b428926ed518b6b63"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-win32.whl", hash = "sha256:e70cce65239089390c193a7b0d171ce89d2e3dedf797f8010031b2aa2b1e9c80"}, + {file = "SQLAlchemy-2.0.26-cp311-cp311-win_amd64.whl", hash = "sha256:750d1ef39d50520527c45c309c3cb10bbfa6131f93081b4e93858abb5ece2501"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4f57af0866f6629eae2d24d022ba1a4c1bac9b16d45027bbfcda4c9d5b0d8f26"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e1a532bc33163fb19c4759a36504a23e63032bc8d47cee1c66b0b70a04a0957b"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02a4f954ccb17bd8cff56662efc806c5301508233dc38d0253a5fdb2f33ca3ba"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a678f728fb075e74aaa7fdc27f8af8f03f82d02e7419362cc8c2a605c16a4114"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8b39462c9588d4780f041e1b84d2ba038ac01c441c961bbee622dd8f53dec69f"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98f4d0d2bda2921af5b0c2ca99207cdab00f2922da46a6336c62c8d6814303a7"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-win32.whl", hash = "sha256:6d68e6b507a3dd20c0add86ac0a0ca061d43c9a0162a122baa5fe952f14240f1"}, + {file = "SQLAlchemy-2.0.26-cp39-cp39-win_amd64.whl", hash = "sha256:fb97a9b93b953084692a52a7877957b7a88dfcedc0c5652124f5aebf5999f7fe"}, + {file = "SQLAlchemy-2.0.26-py3-none-any.whl", hash = "sha256:1128b2cdf49107659f6d1f452695f43a20694cc9305a86e97b70793a1c74eeb4"}, + {file = "SQLAlchemy-2.0.26.tar.gz", hash = "sha256:e1bcd8fcb30305e27355d553608c2c229d3e589fb7ff406da7d7e5d50fa14d0d"}, +] + +[[package]] +name = "sqlparse" +version = "0.4.4" +requires_python = ">=3.5" +summary = "A non-validating SQL parser." +groups = ["default"] +files = [ + {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, + {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, +] + +[[package]] +name = "stone" +version = "3.3.1" +summary = "Stone is an interface description language (IDL) for APIs." +groups = ["default"] +dependencies = [ + "ply>=3.4", + "six>=1.12.0", +] +files = [ + {file = "stone-3.3.1-py3-none-any.whl", hash = "sha256:e15866fad249c11a963cce3bdbed37758f2e88c8ff4898616bc0caeb1e216047"}, + {file = "stone-3.3.1.tar.gz", hash = "sha256:4ef0397512f609757975f7ec09b35639d72ba7e3e17ce4ddf399578346b4cb50"}, +] + +[[package]] +name = "storage3" +version = "0.7.0" +requires_python = ">=3.8,<4.0" +summary = "Supabase Storage client for Python." +groups = ["default"] +dependencies = [ + "httpx<0.26,>=0.24", + "python-dateutil<3.0.0,>=2.8.2", + "typing-extensions<5.0.0,>=4.2.0", +] +files = [ + {file = "storage3-0.7.0-py3-none-any.whl", hash = "sha256:dd2d6e68f7a3dc038047ed62fa8bdc5c2e3d6b6e56ee2951195d084bcce71605"}, + {file = "storage3-0.7.0.tar.gz", hash = "sha256:9ddecc775cdc04514413bd44b9ec61bc25aad9faadabefdb6e6e88b33756f5fd"}, +] + +[[package]] +name = "strenum" +version = "0.4.15" +summary = "An Enum that inherits from str." +groups = ["default"] +files = [ + {file = "StrEnum-0.4.15-py3-none-any.whl", hash = "sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659"}, + {file = "StrEnum-0.4.15.tar.gz", hash = "sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff"}, +] + +[[package]] +name = "supabase" +version = "2.2.1" +requires_python = ">=3.8,<4.0" +summary = "Supabase client for Python." +groups = ["default"] +dependencies = [ + "gotrue<3.0,>=1.3", + "httpx<0.25.0,>=0.24.0", + "postgrest<0.14.0,>=0.10.8", + "realtime<2.0.0,>=1.0.0", + "storage3<0.8.0,>=0.5.3", + "supafunc<0.4.0,>=0.3.1", +] +files = [ + {file = "supabase-2.2.1-py3-none-any.whl", hash = "sha256:ce5a5773e47b009714dad645b5d417cc9759725f807e549f08a65e513cee17d3"}, + {file = "supabase-2.2.1.tar.gz", hash = "sha256:d724c16245b92b0faef5c467dafbb81e561f6b44c56195a076666da1bd327317"}, +] + +[[package]] +name = "supafunc" +version = "0.3.3" +requires_python = ">=3.8,<4.0" +summary = "Library for Supabase Functions" +groups = ["default"] +dependencies = [ + "httpx<0.26,>=0.24", +] +files = [ + {file = "supafunc-0.3.3-py3-none-any.whl", hash = "sha256:8260b4742335932f9cab64c8f66fb6998681b7e8ca7a46b559a4eb640cc0af80"}, + {file = "supafunc-0.3.3.tar.gz", hash = "sha256:c35897a2f40465b40d7a08ae11f872f08eb8d1390c3ebc72c80e27d33ba91b99"}, +] + +[[package]] +name = "sympy" +version = "1.12" +requires_python = ">=3.8" +summary = "Computer algebra system (CAS) in Python" +groups = ["default"] +dependencies = [ + "mpmath>=0.19", +] +files = [ + {file = "sympy-1.12-py3-none-any.whl", hash = "sha256:c3588cd4295d0c0f603d0f2ae780587e64e2efeedb3521e46b9bb1d08d184fa5"}, + {file = "sympy-1.12.tar.gz", hash = "sha256:ebf595c8dac3e0fdc4152c51878b498396ec7f30e7a914d6071e674d49420fb8"}, +] + +[[package]] +name = "tabulate" +version = "0.9.0" +requires_python = ">=3.7" +summary = "Pretty-print tabular data" +groups = ["default"] +files = [ + {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, + {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, +] + +[[package]] +name = "tenacity" +version = "8.2.3" +requires_python = ">=3.7" +summary = "Retry code until it succeeds" +groups = ["default"] +files = [ + {file = "tenacity-8.2.3-py3-none-any.whl", hash = "sha256:ce510e327a630c9e1beaf17d42e6ffacc88185044ad85cf74c0a8887c6a0f88c"}, + {file = "tenacity-8.2.3.tar.gz", hash = "sha256:5398ef0d78e63f40007c1fb4c0bff96e1911394d2fa8d194f77619c05ff6cc8a"}, +] + +[[package]] +name = "tensorrt-llm" +version = "0.7.1" +requires_python = ">=3.7, <4" +summary = "" +groups = ["default"] +marker = "python_version == \"3.10\"" +files = [ + {file = "tensorrt-llm-0.7.1.tar.gz", hash = "sha256:10275e2585484f138b43576acddba42ebee073fbb1665fe0954032e421e26e08"}, +] + +[[package]] +name = "termcolor" +version = "2.4.0" +requires_python = ">=3.8" +summary = "ANSI color formatting for output in terminal" +groups = ["default"] +files = [ + {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, + {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"}, +] + +[[package]] +name = "tiktoken" +version = "0.4.0" +requires_python = ">=3.8" +summary = "tiktoken is a fast BPE tokeniser for use with OpenAI's models" +groups = ["default"] +dependencies = [ + "regex>=2022.1.18", + "requests>=2.26.0", +] +files = [ + {file = "tiktoken-0.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:176cad7f053d2cc82ce7e2a7c883ccc6971840a4b5276740d0b732a2b2011f8a"}, + {file = "tiktoken-0.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:450d504892b3ac80207700266ee87c932df8efea54e05cefe8613edc963c1285"}, + {file = "tiktoken-0.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00d662de1e7986d129139faf15e6a6ee7665ee103440769b8dedf3e7ba6ac37f"}, + {file = "tiktoken-0.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5727d852ead18b7927b8adf558a6f913a15c7766725b23dbe21d22e243041b28"}, + {file = "tiktoken-0.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c06cd92b09eb0404cedce3702fa866bf0d00e399439dad3f10288ddc31045422"}, + {file = "tiktoken-0.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9ec161e40ed44e4210d3b31e2ff426b4a55e8254f1023e5d2595cb60044f8ea6"}, + {file = "tiktoken-0.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:1e8fa13cf9889d2c928b9e258e9dbbbf88ab02016e4236aae76e3b4f82dd8288"}, + {file = "tiktoken-0.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bb2341836b725c60d0ab3c84970b9b5f68d4b733a7bcb80fb25967e5addb9920"}, + {file = "tiktoken-0.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ca30367ad750ee7d42fe80079d3092bd35bb266be7882b79c3bd159b39a17b0"}, + {file = "tiktoken-0.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dc3df19ddec79435bb2a94ee46f4b9560d0299c23520803d851008445671197"}, + {file = "tiktoken-0.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d980fa066e962ef0f4dad0222e63a484c0c993c7a47c7dafda844ca5aded1f3"}, + {file = "tiktoken-0.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:329f548a821a2f339adc9fbcfd9fc12602e4b3f8598df5593cfc09839e9ae5e4"}, + {file = "tiktoken-0.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b1a038cee487931a5caaef0a2e8520e645508cde21717eacc9af3fbda097d8bb"}, + {file = "tiktoken-0.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:08efa59468dbe23ed038c28893e2a7158d8c211c3dd07f2bbc9a30e012512f1d"}, + {file = "tiktoken-0.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8d1d97f83697ff44466c6bef5d35b6bcdb51e0125829a9c0ed1e6e39fb9a08fb"}, + {file = "tiktoken-0.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b6bce7c68aa765f666474c7c11a7aebda3816b58ecafb209afa59c799b0dd2d"}, + {file = "tiktoken-0.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a73286c35899ca51d8d764bc0b4d60838627ce193acb60cc88aea60bddec4fd"}, + {file = "tiktoken-0.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0394967d2236a60fd0aacef26646b53636423cc9c70c32f7c5124ebe86f3093"}, + {file = "tiktoken-0.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:dae2af6f03ecba5f679449fa66ed96585b2fa6accb7fd57d9649e9e398a94f44"}, + {file = "tiktoken-0.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:55e251b1da3c293432179cf7c452cfa35562da286786be5a8b1ee3405c2b0dd2"}, + {file = "tiktoken-0.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:c835d0ee1f84a5aa04921717754eadbc0f0a56cf613f78dfc1cf9ad35f6c3fea"}, + {file = "tiktoken-0.4.0.tar.gz", hash = "sha256:59b20a819969735b48161ced9b92f05dc4519c17be4015cfb73b65270a243620"}, +] + +[[package]] +name = "tokenizers" +version = "0.15.2" +requires_python = ">=3.7" +summary = "" +groups = ["default"] +dependencies = [ + "huggingface-hub<1.0,>=0.16.4", +] +files = [ + {file = "tokenizers-0.15.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:52f6130c9cbf70544287575a985bf44ae1bda2da7e8c24e97716080593638012"}, + {file = "tokenizers-0.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:054c1cc9c6d68f7ffa4e810b3d5131e0ba511b6e4be34157aa08ee54c2f8d9ee"}, + {file = "tokenizers-0.15.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9b9b070fdad06e347563b88c278995735292ded1132f8657084989a4c84a6d5"}, + {file = "tokenizers-0.15.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea621a7eef4b70e1f7a4e84dd989ae3f0eeb50fc8690254eacc08acb623e82f1"}, + {file = "tokenizers-0.15.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf7fd9a5141634fa3aa8d6b7be362e6ae1b4cda60da81388fa533e0b552c98fd"}, + {file = "tokenizers-0.15.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44f2a832cd0825295f7179eaf173381dc45230f9227ec4b44378322d900447c9"}, + {file = "tokenizers-0.15.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8b9ec69247a23747669ec4b0ca10f8e3dfb3545d550258129bd62291aabe8605"}, + {file = "tokenizers-0.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b6a4c78da863ff26dbd5ad9a8ecc33d8a8d97b535172601cf00aee9d7ce9ce"}, + {file = "tokenizers-0.15.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5ab2a4d21dcf76af60e05af8063138849eb1d6553a0d059f6534357bce8ba364"}, + {file = "tokenizers-0.15.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a47acfac7e511f6bbfcf2d3fb8c26979c780a91e06fb5b9a43831b2c0153d024"}, + {file = "tokenizers-0.15.2-cp310-none-win32.whl", hash = "sha256:064ff87bb6acdbd693666de9a4b692add41308a2c0ec0770d6385737117215f2"}, + {file = "tokenizers-0.15.2-cp310-none-win_amd64.whl", hash = "sha256:3b919afe4df7eb6ac7cafd2bd14fb507d3f408db7a68c43117f579c984a73843"}, + {file = "tokenizers-0.15.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:89cd1cb93e4b12ff39bb2d626ad77e35209de9309a71e4d3d4672667b4b256e7"}, + {file = "tokenizers-0.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cfed5c64e5be23d7ee0f0e98081a25c2a46b0b77ce99a4f0605b1ec43dd481fa"}, + {file = "tokenizers-0.15.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a907d76dcfda37023ba203ab4ceeb21bc5683436ebefbd895a0841fd52f6f6f2"}, + {file = "tokenizers-0.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20ea60479de6fc7b8ae756b4b097572372d7e4032e2521c1bbf3d90c90a99ff0"}, + {file = "tokenizers-0.15.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:48e2b9335be2bc0171df9281385c2ed06a15f5cf121c44094338306ab7b33f2c"}, + {file = "tokenizers-0.15.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:112a1dd436d2cc06e6ffdc0b06d55ac019a35a63afd26475205cb4b1bf0bfbff"}, + {file = "tokenizers-0.15.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4620cca5c2817177ee8706f860364cc3a8845bc1e291aaf661fb899e5d1c45b0"}, + {file = "tokenizers-0.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccd73a82751c523b3fc31ff8194702e4af4db21dc20e55b30ecc2079c5d43cb7"}, + {file = "tokenizers-0.15.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:107089f135b4ae7817affe6264f8c7a5c5b4fd9a90f9439ed495f54fcea56fb4"}, + {file = "tokenizers-0.15.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0ff110ecc57b7aa4a594396525a3451ad70988e517237fe91c540997c4e50e29"}, + {file = "tokenizers-0.15.2-cp311-none-win32.whl", hash = "sha256:6d76f00f5c32da36c61f41c58346a4fa7f0a61be02f4301fd30ad59834977cc3"}, + {file = "tokenizers-0.15.2-cp311-none-win_amd64.whl", hash = "sha256:cc90102ed17271cf0a1262babe5939e0134b3890345d11a19c3145184b706055"}, + {file = "tokenizers-0.15.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:82f8652a74cc107052328b87ea8b34291c0f55b96d8fb261b3880216a9f9e48e"}, + {file = "tokenizers-0.15.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:02458bee6f5f3139f1ebbb6d042b283af712c0981f5bc50edf771d6b762d5e4f"}, + {file = "tokenizers-0.15.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c9a09cd26cca2e1c349f91aa665309ddb48d71636370749414fbf67bc83c5343"}, + {file = "tokenizers-0.15.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:158be8ea8554e5ed69acc1ce3fbb23a06060bd4bbb09029431ad6b9a466a7121"}, + {file = "tokenizers-0.15.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ddba9a2b0c8c81633eca0bb2e1aa5b3a15362b1277f1ae64176d0f6eba78ab1"}, + {file = "tokenizers-0.15.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ef5dd1d39797044642dbe53eb2bc56435308432e9c7907728da74c69ee2adca"}, + {file = "tokenizers-0.15.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:454c203164e07a860dbeb3b1f4a733be52b0edbb4dd2e5bd75023ffa8b49403a"}, + {file = "tokenizers-0.15.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cf6b7f1d4dc59af960e6ffdc4faffe6460bbfa8dce27a58bf75755ffdb2526d"}, + {file = "tokenizers-0.15.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2ef09bbc16519f6c25d0c7fc0c6a33a6f62923e263c9d7cca4e58b8c61572afb"}, + {file = "tokenizers-0.15.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c9a2ebdd2ad4ec7a68e7615086e633857c85e2f18025bd05d2a4399e6c5f7169"}, + {file = "tokenizers-0.15.2-cp39-none-win32.whl", hash = "sha256:918fbb0eab96fe08e72a8c2b5461e9cce95585d82a58688e7f01c2bd546c79d0"}, + {file = "tokenizers-0.15.2-cp39-none-win_amd64.whl", hash = "sha256:524e60da0135e106b254bd71f0659be9f89d83f006ea9093ce4d1fab498c6d0d"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6a9b648a58281c4672212fab04e60648fde574877d0139cd4b4f93fe28ca8944"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7c7d18b733be6bbca8a55084027f7be428c947ddf871c500ee603e375013ffba"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:13ca3611de8d9ddfbc4dc39ef54ab1d2d4aaa114ac8727dfdc6a6ec4be017378"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:237d1bf3361cf2e6463e6c140628e6406766e8b27274f5fcc62c747ae3c6f094"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67a0fe1e49e60c664915e9fb6b0cb19bac082ab1f309188230e4b2920230edb3"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4e022fe65e99230b8fd89ebdfea138c24421f91c1a4f4781a8f5016fd5cdfb4d"}, + {file = "tokenizers-0.15.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d857be2df69763362ac699f8b251a8cd3fac9d21893de129bc788f8baaef2693"}, + {file = "tokenizers-0.15.2-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:708bb3e4283177236309e698da5fcd0879ce8fd37457d7c266d16b550bcbbd18"}, + {file = "tokenizers-0.15.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:64c35e09e9899b72a76e762f9854e8750213f67567787d45f37ce06daf57ca78"}, + {file = "tokenizers-0.15.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1257f4394be0d3b00de8c9e840ca5601d0a4a8438361ce9c2b05c7d25f6057b"}, + {file = "tokenizers-0.15.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02272fe48280e0293a04245ca5d919b2c94a48b408b55e858feae9618138aeda"}, + {file = "tokenizers-0.15.2-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dc3ad9ebc76eabe8b1d7c04d38be884b8f9d60c0cdc09b0aa4e3bcf746de0388"}, + {file = "tokenizers-0.15.2-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:32e16bdeffa7c4f46bf2152172ca511808b952701d13e7c18833c0b73cb5c23f"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fb16ba563d59003028b678d2361a27f7e4ae0ab29c7a80690efa20d829c81fdb"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:2277c36d2d6cdb7876c274547921a42425b6810d38354327dd65a8009acf870c"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1cf75d32e8d250781940d07f7eece253f2fe9ecdb1dc7ba6e3833fa17b82fcbc"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1b3b31884dc8e9b21508bb76da80ebf7308fdb947a17affce815665d5c4d028"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b10122d8d8e30afb43bb1fe21a3619f62c3e2574bff2699cf8af8b0b6c5dc4a3"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d88b96ff0fe8e91f6ef01ba50b0d71db5017fa4e3b1d99681cec89a85faf7bf7"}, + {file = "tokenizers-0.15.2-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:37aaec5a52e959892870a7c47cef80c53797c0db9149d458460f4f31e2fb250e"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e2ea752f2b0fe96eb6e2f3adbbf4d72aaa1272079b0dfa1145507bd6a5d537e6"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4b19a808d8799fda23504a5cd31d2f58e6f52f140380082b352f877017d6342b"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:64c86e5e068ac8b19204419ed8ca90f9d25db20578f5881e337d203b314f4104"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de19c4dc503c612847edf833c82e9f73cd79926a384af9d801dcf93f110cea4e"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea09acd2fe3324174063d61ad620dec3bcf042b495515f27f638270a7d466e8b"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cf27fd43472e07b57cf420eee1e814549203d56de00b5af8659cb99885472f1f"}, + {file = "tokenizers-0.15.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:7ca22bd897537a0080521445d91a58886c8c04084a6a19e6c78c586e0cfa92a5"}, + {file = "tokenizers-0.15.2.tar.gz", hash = "sha256:e6e9c6e019dd5484be5beafc775ae6c925f4c69a3487040ed09b45e13df2cb91"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +requires_python = ">=3.7" +summary = "A lil' TOML parser" +groups = ["test"] +marker = "python_version < \"3.11\"" +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 = "tomlkit" +version = "0.12.3" +requires_python = ">=3.7" +summary = "Style preserving TOML library" +groups = ["default"] +files = [ + {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, + {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, +] + +[[package]] +name = "tornado" +version = "6.4" +requires_python = ">= 3.8" +summary = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +groups = ["default"] +files = [ + {file = "tornado-6.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0"}, + {file = "tornado-6.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f"}, + {file = "tornado-6.4-cp38-abi3-win32.whl", hash = "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052"}, + {file = "tornado-6.4-cp38-abi3-win_amd64.whl", hash = "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63"}, + {file = "tornado-6.4.tar.gz", hash = "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee"}, +] + +[[package]] +name = "tqdm" +version = "4.66.2" +requires_python = ">=3.7" +summary = "Fast, Extensible Progress Meter" +groups = ["default"] +dependencies = [ + "colorama; platform_system == \"Windows\"", +] +files = [ + {file = "tqdm-4.66.2-py3-none-any.whl", hash = "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9"}, + {file = "tqdm-4.66.2.tar.gz", hash = "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531"}, +] + +[[package]] +name = "transformers" +version = "4.37.0" +requires_python = ">=3.8.0" +summary = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow" +groups = ["default"] +dependencies = [ + "filelock", + "huggingface-hub<1.0,>=0.19.3", + "numpy>=1.17", + "packaging>=20.0", + "pyyaml>=5.1", + "regex!=2019.12.17", + "requests", + "safetensors>=0.3.1", + "tokenizers<0.19,>=0.14", + "tqdm>=4.27", +] +files = [ + {file = "transformers-4.37.0-py3-none-any.whl", hash = "sha256:669d4e2c12661e71c464eb18d6a9b9a2c74d4cba0f4648bb9323896bdd046826"}, + {file = "transformers-4.37.0.tar.gz", hash = "sha256:5a0fdee36168f751770f7036ce7a8787be14f8b0d8f29806c493b6cb819c6c83"}, +] + +[[package]] +name = "typing-extensions" +version = "4.9.0" +requires_python = ">=3.8" +summary = "Backported and Experimental Type Hints for Python 3.8+" +groups = ["default"] +files = [ + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, +] + +[[package]] +name = "typing-inspect" +version = "0.9.0" +summary = "Runtime inspection utilities for typing module." +groups = ["default"] +dependencies = [ + "mypy-extensions>=0.3.0", + "typing-extensions>=3.7.4", +] +files = [ + {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, + {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, +] + +[[package]] +name = "tzdata" +version = "2024.1" +requires_python = ">=2" +summary = "Provider of IANA time zone data" +groups = ["default"] +files = [ + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, +] + +[[package]] +name = "tzlocal" +version = "5.2" +requires_python = ">=3.8" +summary = "tzinfo object for the local timezone" +groups = ["default"] +dependencies = [ + "tzdata; platform_system == \"Windows\"", +] +files = [ + {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"}, + {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"}, +] + +[[package]] +name = "ujson" +version = "5.9.0" +requires_python = ">=3.8" +summary = "Ultra fast JSON encoder and decoder for Python" +groups = ["default"] +files = [ + {file = "ujson-5.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ab71bf27b002eaf7d047c54a68e60230fbd5cd9da60de7ca0aa87d0bccead8fa"}, + {file = "ujson-5.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a365eac66f5aa7a7fdf57e5066ada6226700884fc7dce2ba5483538bc16c8c5"}, + {file = "ujson-5.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e015122b337858dba5a3dc3533af2a8fc0410ee9e2374092f6a5b88b182e9fcc"}, + {file = "ujson-5.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:779a2a88c53039bebfbccca934430dabb5c62cc179e09a9c27a322023f363e0d"}, + {file = "ujson-5.9.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10ca3c41e80509fd9805f7c149068fa8dbee18872bbdc03d7cca928926a358d5"}, + {file = "ujson-5.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a566e465cb2fcfdf040c2447b7dd9718799d0d90134b37a20dff1e27c0e9096"}, + {file = "ujson-5.9.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f833c529e922577226a05bc25b6a8b3eb6c4fb155b72dd88d33de99d53113124"}, + {file = "ujson-5.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b68a0caab33f359b4cbbc10065c88e3758c9f73a11a65a91f024b2e7a1257106"}, + {file = "ujson-5.9.0-cp310-cp310-win32.whl", hash = "sha256:7cc7e605d2aa6ae6b7321c3ae250d2e050f06082e71ab1a4200b4ae64d25863c"}, + {file = "ujson-5.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:a6d3f10eb8ccba4316a6b5465b705ed70a06011c6f82418b59278fbc919bef6f"}, + {file = "ujson-5.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b23bbb46334ce51ddb5dded60c662fbf7bb74a37b8f87221c5b0fec1ec6454b"}, + {file = "ujson-5.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6974b3a7c17bbf829e6c3bfdc5823c67922e44ff169851a755eab79a3dd31ec0"}, + {file = "ujson-5.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5964ea916edfe24af1f4cc68488448fbb1ec27a3ddcddc2b236da575c12c8ae"}, + {file = "ujson-5.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ba7cac47dd65ff88571eceeff48bf30ed5eb9c67b34b88cb22869b7aa19600d"}, + {file = "ujson-5.9.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bbd91a151a8f3358c29355a491e915eb203f607267a25e6ab10531b3b157c5e"}, + {file = "ujson-5.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:829a69d451a49c0de14a9fecb2a2d544a9b2c884c2b542adb243b683a6f15908"}, + {file = "ujson-5.9.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a807ae73c46ad5db161a7e883eec0fbe1bebc6a54890152ccc63072c4884823b"}, + {file = "ujson-5.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8fc2aa18b13d97b3c8ccecdf1a3c405f411a6e96adeee94233058c44ff92617d"}, + {file = "ujson-5.9.0-cp311-cp311-win32.whl", hash = "sha256:70e06849dfeb2548be48fdd3ceb53300640bc8100c379d6e19d78045e9c26120"}, + {file = "ujson-5.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:7309d063cd392811acc49b5016728a5e1b46ab9907d321ebbe1c2156bc3c0b99"}, + {file = "ujson-5.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d0fd2eba664a22447102062814bd13e63c6130540222c0aa620701dd01f4be81"}, + {file = "ujson-5.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bdf7fc21a03bafe4ba208dafa84ae38e04e5d36c0e1c746726edf5392e9f9f36"}, + {file = "ujson-5.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2f909bc08ce01f122fd9c24bc6f9876aa087188dfaf3c4116fe6e4daf7e194f"}, + {file = "ujson-5.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd4ea86c2afd41429751d22a3ccd03311c067bd6aeee2d054f83f97e41e11d8f"}, + {file = "ujson-5.9.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:63fb2e6599d96fdffdb553af0ed3f76b85fda63281063f1cb5b1141a6fcd0617"}, + {file = "ujson-5.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:32bba5870c8fa2a97f4a68f6401038d3f1922e66c34280d710af00b14a3ca562"}, + {file = "ujson-5.9.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:37ef92e42535a81bf72179d0e252c9af42a4ed966dc6be6967ebfb929a87bc60"}, + {file = "ujson-5.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f69f16b8f1c69da00e38dc5f2d08a86b0e781d0ad3e4cc6a13ea033a439c4844"}, + {file = "ujson-5.9.0-cp39-cp39-win32.whl", hash = "sha256:3382a3ce0ccc0558b1c1668950008cece9bf463ebb17463ebf6a8bfc060dae34"}, + {file = "ujson-5.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:6adef377ed583477cf005b58c3025051b5faa6b8cc25876e594afbb772578f21"}, + {file = "ujson-5.9.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ffdfebd819f492e48e4f31c97cb593b9c1a8251933d8f8972e81697f00326ff1"}, + {file = "ujson-5.9.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4eec2ddc046360d087cf35659c7ba0cbd101f32035e19047013162274e71fcf"}, + {file = "ujson-5.9.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbb90aa5c23cb3d4b803c12aa220d26778c31b6e4b7a13a1f49971f6c7d088e"}, + {file = "ujson-5.9.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba0823cb70866f0d6a4ad48d998dd338dce7314598721bc1b7986d054d782dfd"}, + {file = "ujson-5.9.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:4e35d7885ed612feb6b3dd1b7de28e89baaba4011ecdf995e88be9ac614765e9"}, + {file = "ujson-5.9.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b048aa93eace8571eedbd67b3766623e7f0acbf08ee291bef7d8106210432427"}, + {file = "ujson-5.9.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:323279e68c195110ef85cbe5edce885219e3d4a48705448720ad925d88c9f851"}, + {file = "ujson-5.9.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ac92d86ff34296f881e12aa955f7014d276895e0e4e868ba7fddebbde38e378"}, + {file = "ujson-5.9.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6eecbd09b316cea1fd929b1e25f70382917542ab11b692cb46ec9b0a26c7427f"}, + {file = "ujson-5.9.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:473fb8dff1d58f49912323d7cb0859df5585cfc932e4b9c053bf8cf7f2d7c5c4"}, + {file = "ujson-5.9.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f91719c6abafe429c1a144cfe27883eace9fb1c09a9c5ef1bcb3ae80a3076a4e"}, + {file = "ujson-5.9.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b1c0991c4fe256f5fdb19758f7eac7f47caac29a6c57d0de16a19048eb86bad"}, + {file = "ujson-5.9.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a8ea0f55a1396708e564595aaa6696c0d8af532340f477162ff6927ecc46e21"}, + {file = "ujson-5.9.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:07e0cfdde5fd91f54cd2d7ffb3482c8ff1bf558abf32a8b953a5d169575ae1cd"}, + {file = "ujson-5.9.0.tar.gz", hash = "sha256:89cc92e73d5501b8a7f48575eeb14ad27156ad092c2e9fc7e3cf949f07e75532"}, +] + +[[package]] +name = "unstract-adapters" +version = "0.2.1" +requires_python = "<3.12,>=3.9" +summary = "Unstract Adapters" +groups = ["default"] +dependencies = [ + "SQLAlchemy==2.0.26", + "anthropic==0.7.8", + "anyscale==0.5.165", + "asyncpg==0.29.0", + "fastembed==0.1.3", + "flupy==1.2.0", + "google-cloud-aiplatform==1.40.0", + "google-generativeai==0.3.1", + "huggingface==0.0.1", + "llama-index==0.9.28", + "mistralai==0.0.8", + "openai==1.3.9", + "pgvector==0.1.*", + "pinecone-client==2.2.4", + "psycopg2-binary==2.9.9", + "pymilvus==2.3.4", + "qdrant-client==1.7.0", + "replicate==0.22.0", + "supabase==2.2.1", + "vecs==0.1.0", + "weaviate-client==3.25.3", +] +files = [ + {file = "unstract_adapters-0.2.1-py3-none-any.whl", hash = "sha256:7b48707bc5c634f07d4ea2926f1b2925bcd5c6869e057839ba69c2d62d19941b"}, + {file = "unstract_adapters-0.2.1.tar.gz", hash = "sha256:08646a232185185390a193ad12b16715d1fccc69195d2d28e4f291b5c55f8117"}, +] + +[[package]] +name = "unstract-connectors" +version = "0.0.3" +requires_python = ">=3.9" +path = "../unstract/connectors" +summary = "All connectors that are part of the Unstract platform" +groups = ["default"] +dependencies = [ + "PyDrive2[fsspec]==1.15.4", + "PyMySQL==1.1.0", + "boxfs==0.2.1", + "dropboxdrivefs==1.3.1", + "google-auth==2.20.0", + "google-cloud-bigquery==3.11.4", + "google-cloud-secret-manager==2.16.1", + "google-cloud-storage==2.9.0", + "oauth2client==4.1.3", + "psycopg2-binary==2.9.9", + "pymssql==2.2.8", + "s3fs[boto3]==2023.6.0", + "snowflake-connector-python[pandas]~=3.6.0", +] + +[[package]] +name = "unstract-core" +version = "0.0.1" +requires_python = ">=3.9,<3.11.1" +path = "../unstract/core" +summary = "Core library that helps with executing workflows." +groups = ["default"] +dependencies = [ + "boto3~=1.28.17", + "botocore~=1.31.17", + "llama-index==0.9.28", + "redis~=5.0.1", + "requests==2.31.0", +] + +[[package]] +name = "unstract-flags" +version = "0.0.1" +requires_python = ">=3.9" +path = "../unstract/flags" +summary = "Unstract's feature flags package." +groups = ["default"] +dependencies = [ + "grpcio-tools<=1.58.0", + "grpcio<=1.58.0", +] + +[[package]] +name = "unstract-sdk" +version = "0.11.1" +requires_python = "<3.11.1,>=3.9" +summary = "A framework for writing Unstract Tools/Apps" +groups = ["default"] +dependencies = [ + "filetype==1.2.0", + "jsonschema~=4.18.2", + "llama-index==0.9.28", + "pdfplumber==0.10.3", + "pytesseract==0.3.10", + "python-dotenv==1.0.0", + "python-magic~=0.4.27", + "tiktoken~=0.4.0", + "transformers==4.37.0", + "unstract-adapters~=0.2.1", +] +files = [ + {file = "unstract_sdk-0.11.1-py3-none-any.whl", hash = "sha256:c969050363874b88d5024623ddfa2f7e9e55726b7c774cb96494835f5c7a5037"}, + {file = "unstract_sdk-0.11.1.tar.gz", hash = "sha256:8440f64851449f5962027e563d30b5fa21a3113ca9e65730b8909abff89995e5"}, +] + +[[package]] +name = "unstract-tool-registry" +version = "0.0.1" +requires_python = ">=3.9,<3.11.1" +path = "../unstract/tool-registry" +summary = "Unstract's registry of tools to be used in workflows." +groups = ["default"] +dependencies = [ + "PyYAML~=6.0.1", + "docker~=6.1.3", + "jsonschema~=4.18.2", + "unstract-adapters~=0.2.1", + "unstract-tool-sandbox @ file:///home/chandru/zipstuff/Pandora/unstract/tool-registry/../tool-sandbox", +] + +[[package]] +name = "unstract-tool-sandbox" +version = "0.0.1" +requires_python = ">=3.9" +path = "../unstract/tool-sandbox" +summary = "Unstract Tool Sandbox is a package to communicate with tool worker" +groups = ["default"] +dependencies = [ + "requests==2.31.0", +] + +[[package]] +name = "unstract-workflow-execution" +version = "0.0.1" +requires_python = ">=3.9" +path = "../unstract/workflow-execution" +summary = "Unstract workflow execution package" +groups = ["default"] +dependencies = [ + "unstract-tool-registry", + "unstract-tool-sandbox", +] + +[[package]] +name = "uritemplate" +version = "4.1.1" +requires_python = ">=3.6" +summary = "Implementation of RFC 6570 URI Templates" +groups = ["default"] +files = [ + {file = "uritemplate-4.1.1-py2.py3-none-any.whl", hash = "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e"}, + {file = "uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0"}, +] + +[[package]] +name = "urllib3" +version = "1.26.18" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +summary = "HTTP library with thread-safe connection pooling, file post, and more." +groups = ["default"] +files = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] + +[[package]] +name = "validators" +version = "0.22.0" +requires_python = ">=3.8" +summary = "Python Data Validation for Humans™" +groups = ["default"] +files = [ + {file = "validators-0.22.0-py3-none-any.whl", hash = "sha256:61cf7d4a62bbae559f2e54aed3b000cea9ff3e2fdbe463f51179b92c58c9585a"}, + {file = "validators-0.22.0.tar.gz", hash = "sha256:77b2689b172eeeb600d9605ab86194641670cdb73b60afd577142a9397873370"}, +] + +[[package]] +name = "vecs" +version = "0.1.0" +summary = "pgvector client" +groups = ["default"] +dependencies = [ + "pgvector==0.1.*", + "sqlalchemy==2.*", +] +files = [ + {file = "vecs-0.1.0.tar.gz", hash = "sha256:a651c349b7bbbdcaf8f19cd3319fc438308617fdf6e664db09fdaa4752985e42"}, +] + +[[package]] +name = "vine" +version = "5.1.0" +requires_python = ">=3.6" +summary = "Python promises." +groups = ["default"] +files = [ + {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, + {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, +] + +[[package]] +name = "wcwidth" +version = "0.2.13" +summary = "Measures the displayed width of unicode strings in a terminal" +groups = ["default"] +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + +[[package]] +name = "weaviate-client" +version = "3.25.3" +requires_python = ">=3.8" +summary = "A python native Weaviate client" +groups = ["default"] +dependencies = [ + "authlib<2.0.0,>=1.2.1", + "requests<3.0.0,>=2.30.0", + "validators<1.0.0,>=0.21.2", +] +files = [ + {file = "weaviate-client-3.25.3.tar.gz", hash = "sha256:894df700fc1f0a932fa370029f644af4062f8718026fda5ad07647d357d95167"}, + {file = "weaviate_client-3.25.3-py3-none-any.whl", hash = "sha256:cb049ed7b710088ff9038d27b97f28c80206ce9e4d12d622c3597da5790b2be0"}, +] + +[[package]] +name = "websocket-client" +version = "1.7.0" +requires_python = ">=3.8" +summary = "WebSocket client for Python with low level API options" +groups = ["default"] +files = [ + {file = "websocket-client-1.7.0.tar.gz", hash = "sha256:10e511ea3a8c744631d3bd77e61eb17ed09304c413ad42cf6ddfa4c7787e8fe6"}, + {file = "websocket_client-1.7.0-py3-none-any.whl", hash = "sha256:f4c3d22fec12a2461427a29957ff07d35098ee2d976d3ba244e688b8b4057588"}, +] + +[[package]] +name = "websockets" +version = "11.0.3" +requires_python = ">=3.7" +summary = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +groups = ["default"] +files = [ + {file = "websockets-11.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac"}, + {file = "websockets-11.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d"}, + {file = "websockets-11.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f"}, + {file = "websockets-11.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564"}, + {file = "websockets-11.0.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11"}, + {file = "websockets-11.0.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca"}, + {file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54"}, + {file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4"}, + {file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526"}, + {file = "websockets-11.0.3-cp310-cp310-win32.whl", hash = "sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69"}, + {file = "websockets-11.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f"}, + {file = "websockets-11.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb"}, + {file = "websockets-11.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288"}, + {file = "websockets-11.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d"}, + {file = "websockets-11.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3"}, + {file = "websockets-11.0.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b"}, + {file = "websockets-11.0.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6"}, + {file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97"}, + {file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf"}, + {file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd"}, + {file = "websockets-11.0.3-cp311-cp311-win32.whl", hash = "sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c"}, + {file = "websockets-11.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8"}, + {file = "websockets-11.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:777354ee16f02f643a4c7f2b3eff8027a33c9861edc691a2003531f5da4f6bc8"}, + {file = "websockets-11.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8c82f11964f010053e13daafdc7154ce7385ecc538989a354ccc7067fd7028fd"}, + {file = "websockets-11.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3580dd9c1ad0701169e4d6fc41e878ffe05e6bdcaf3c412f9d559389d0c9e016"}, + {file = "websockets-11.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f1a3f10f836fab6ca6efa97bb952300b20ae56b409414ca85bff2ad241d2a61"}, + {file = "websockets-11.0.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df41b9bc27c2c25b486bae7cf42fccdc52ff181c8c387bfd026624a491c2671b"}, + {file = "websockets-11.0.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:279e5de4671e79a9ac877427f4ac4ce93751b8823f276b681d04b2156713b9dd"}, + {file = "websockets-11.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1fdf26fa8a6a592f8f9235285b8affa72748dc12e964a5518c6c5e8f916716f7"}, + {file = "websockets-11.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:69269f3a0b472e91125b503d3c0b3566bda26da0a3261c49f0027eb6075086d1"}, + {file = "websockets-11.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:97b52894d948d2f6ea480171a27122d77af14ced35f62e5c892ca2fae9344311"}, + {file = "websockets-11.0.3-cp39-cp39-win32.whl", hash = "sha256:c7f3cb904cce8e1be667c7e6fef4516b98d1a6a0635a58a57528d577ac18a128"}, + {file = "websockets-11.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c792ea4eabc0159535608fc5658a74d1a81020eb35195dd63214dcf07556f67e"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602"}, + {file = "websockets-11.0.3-py3-none-any.whl", hash = "sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6"}, + {file = "websockets-11.0.3.tar.gz", hash = "sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016"}, +] + +[[package]] +name = "win32-setctime" +version = "1.1.0" +requires_python = ">=3.5" +summary = "A small Python utility to set file creation time on Windows" +groups = ["default"] +marker = "sys_platform == \"win32\"" +files = [ + {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, + {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, +] + +[[package]] +name = "wrapt" +version = "1.16.0" +requires_python = ">=3.6" +summary = "Module for decorators, wrappers and monkey patching." +groups = ["default"] +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-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" +requires_python = ">=3.7.0" +summary = "WebSockets state-machine based protocol implementation" +groups = ["default"] +dependencies = [ + "h11<1,>=0.9.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]] +name = "yarl" +version = "1.9.4" +requires_python = ">=3.7" +summary = "Yet another URL library" +groups = ["default"] +dependencies = [ + "idna>=2.0", + "multidict>=4.0", +] +files = [ + {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, + {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, + {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, + {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, + {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, + {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, + {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, + {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, + {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, + {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, + {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, +] diff --git a/backend/permissions/__init__.py b/backend/permissions/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/permissions/permission.py b/backend/permissions/permission.py new file mode 100644 index 000000000..c8fa219b9 --- /dev/null +++ b/backend/permissions/permission.py @@ -0,0 +1,14 @@ +from typing import Any + +from rest_framework import permissions +from rest_framework.request import Request +from rest_framework.views import APIView + + +class IsOwner(permissions.BasePermission): + """Custom permission to only allow owners of an object to edit it.""" + + def has_object_permission( + self, request: Request, view: APIView, obj: Any + ) -> bool: + return True if obj.created_by == request.user else False diff --git a/backend/pipeline/__init__.py b/backend/pipeline/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/pipeline/constants.py b/backend/pipeline/constants.py new file mode 100644 index 000000000..42211de6d --- /dev/null +++ b/backend/pipeline/constants.py @@ -0,0 +1,65 @@ +class PipelineConstants: + """Constants for Pipelines.""" + + TYPE = "type" + ETL_PIPELINE = "ETL" + TASK_PIPELINE = "TASK" + ETL = "etl" + TASK = "task" + CREATE_ACTION = "create" + UPDATE_ACTION = "update" + PIPELINE_GUID = "id" + ACTION = "action" + NOT_CONFIGURED = "Connector not configured." + SOURCE_NOT_CONFIGURED = "Source not configured." + DESTINATION_NOT_CONFIGURED = "Destination not configured." + SOURCE_ICON = "source_icon" + DESTINATION_ICON = "destination_icon" + SOURCE_NAME = "source_name" + DESTINATION_NAME = "destination_name" + INPUT_FILE = "input_file_connector" + INPUT_DB = "input_db_connector" + OUTPUT_FILE = "output_file_connector" + OUTPUT_DB = "output_db_connector" + SOURCE = "source" + DEST = "dest" + + +class PipelineExecutionKey: + PIPELINE = "pipeline" + EXECUTION = "execution" + + +class PipelineKey: + """Constants for the Pipeline model.""" + + PIPELINE_GUID = "id" + PIPELINE_NAME = "pipeline_name" + WORKFLOW = "workflow" + APP_ID = "app_id" + ACTIVE = "active" + SCHEDULED = "scheduled" + PIPELINE_TYPE = "pipeline_type" + RUN_COUNT = "run_count" + LAST_RUN_TIME = "last_run_time" + LAST_RUN_STATUS = "last_run_status" + # Used by serializer + CRON_DATA = "cron_data" + WORKFLOW_NAME = "workflow_name" + WORKFLOW_ID = "workflow_id" + CRON_SUMMARY = "cron_summary" + PIPELINE_ID = "pipeline_id" + + +class PipelineErrors: + PIPELINE_EXISTS = "Pipeline with this configuration might already exist or some mandatory field is missing." # noqa: E501 + DUPLICATE_API = "It appears that a duplicate call may have been made." + INVALID_WF = "The provided workflow does not exist" + + +class PipelineURL: + """Constants for URL names.""" + + DETAIL = "pipeline-detail" + LIST = "pipeline-list" + EXECUTE = "pipeline-execute" diff --git a/backend/pipeline/exceptions.py b/backend/pipeline/exceptions.py new file mode 100644 index 000000000..da8c9dff7 --- /dev/null +++ b/backend/pipeline/exceptions.py @@ -0,0 +1,36 @@ +from rest_framework.exceptions import APIException + + +class PipelineSaveError(APIException): + status_code = 500 + default_detail = "Error saving pipeline" + + +class WorkflowTriggerError(APIException): + status_code = 400 + default_detail = "Error triggering workflow. Pipeline created" + + +class PipelineExecuteError(APIException): + status_code = 500 + default_detail = "Error executing pipline" + + +class InactivePipelineError(APIException): + status_code = 422 + default_detail = "Pipeline is inactive, please activate the pipeline" + + +class MandatoryPipelineType(APIException): + status_code = 400 + default_detail = "Pipeline type is mandatory" + + +class MandatoryWorkflowId(APIException): + status_code = 400 + default_detail = "Workflow ID is mandatory" + + +class MandatoryCronSchedule(APIException): + status_code = 400 + default_detail = "Cron schedule is mandatory" diff --git a/backend/pipeline/manager.py b/backend/pipeline/manager.py new file mode 100644 index 000000000..fbbef4876 --- /dev/null +++ b/backend/pipeline/manager.py @@ -0,0 +1,82 @@ +import logging +from typing import Any, Optional + +from backend.constants import RequestHeader +from django.conf import settings +from django.urls import reverse +from pipeline.constants import PipelineKey, PipelineURL +from pipeline.exceptions import PipelineExecuteError +from pipeline.models import Pipeline +from pipeline.pipeline_processor import PipelineProcessor +from rest_framework.request import Request +from rest_framework.response import Response +from utils.request.constants import RequestConstants +from workflow_manager.workflow.constants import WorkflowExecutionKey, WorkflowKey +from workflow_manager.workflow.views import WorkflowViewSet + +logger = logging.getLogger(__name__) + + +class PipelineManager: + """Helps manage the execution and scheduling of pipelines.""" + + @staticmethod + def execute_pipeline( + request: Request, + pipeline_id: str, + execution_id: Optional[str] = None, + with_log: Optional[bool] = None, + ) -> Response: + """Used to execute a pipeline. + + Args: + pipeline_id (str): UUID of the pipeline to execute + execution_id (Optional[str], optional): + Uniquely identifies an execution. Defaults to None. + with_log (Optional[bool], optional): Flag to pass logs to FE. + Defaults to None. + """ + logger.info( + f"Executing pipeline {pipeline_id}, execution: {execution_id}, " + f"with_log = {with_log}" + ) + try: + pipeline: Pipeline = PipelineProcessor.initialize_pipeline_sync( + pipeline_id + ) + # TODO: Use DRF's request and as_view() instead + request.data[WorkflowKey.WF_ID] = pipeline.workflow.id + if execution_id is not None: + request.data[WorkflowExecutionKey.EXECUTION_ID] = execution_id + wf_viewset = WorkflowViewSet() + return WorkflowViewSet.execute( + wf_viewset, + request=request, + pipeline_guid=pipeline.pk, + with_log=with_log, + ) + except Exception as e: + logger.error(f"Error executing pipeline: {e}") + raise PipelineExecuteError() + + @staticmethod + def get_pipeline_execution_data_for_scheduled_run( + pipeline_id: str, + ) -> Optional[dict[str, Any]]: + """Gets the required data to be passed while executing a pipeline Any + changes to pipeline execution needs to be propagated here.""" + callback_url = settings.DJANGO_APP_BACKEND_URL + reverse( + PipelineURL.EXECUTE + ) + job_headers = { + RequestHeader.X_API_KEY: settings.INTERNAL_SERVICE_API_KEY + } + job_params = {WorkflowExecutionKey.WITH_LOG: "False"} + job_kwargs = { + RequestConstants.VERB: "POST", + RequestConstants.URL: callback_url, + RequestConstants.HEADERS: job_headers, + RequestConstants.PARAMS: job_params, + RequestConstants.DATA: {PipelineKey.PIPELINE_ID: pipeline_id}, + } + return job_kwargs diff --git a/backend/pipeline/migrations/0001_initial.py b/backend/pipeline/migrations/0001_initial.py new file mode 100644 index 000000000..828bae01b --- /dev/null +++ b/backend/pipeline/migrations/0001_initial.py @@ -0,0 +1,132 @@ +# Generated by Django 4.2.1 on 2024-01-23 11:18 + +import uuid + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("workflow", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="Pipeline", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "pipeline_name", + models.CharField(default="", max_length=32, unique=True), + ), + ( + "app_id", + models.TextField(blank=True, max_length=32, null=True), + ), + ("active", models.BooleanField(default=False)), + ("scheduled", models.BooleanField(default=False)), + ( + "cron_string", + models.TextField( + db_comment="UNIX cron string", max_length=256 + ), + ), + ( + "pipeline_type", + models.CharField( + choices=[ + ("ETL", "ETL"), + ("TASK", "TASK"), + ("DEFAULT", "Default"), + ("APP", "App"), + ], + default="DEFAULT", + ), + ), + ("run_count", models.IntegerField(default=0)), + ("last_run_time", models.DateTimeField(blank=True, null=True)), + ( + "last_run_status", + models.CharField( + choices=[ + ("SUCCESS", "Success"), + ("FAILURE", "Failure"), + ("INPROGRESS", "Inprogress"), + ("YET_TO_START", "Yet to start"), + ("RESTARTING", "Restarting"), + ], + default="YET_TO_START", + ), + ), + ( + "app_icon", + models.URLField( + blank=True, + db_comment="Field to store icon url for Apps", + null=True, + ), + ), + ( + "app_url", + models.URLField( + blank=True, + db_comment="Stores deployed URL for App", + null=True, + ), + ), + ( + "access_control_bundle_id", + models.TextField(blank=True, null=True), + ), + ( + "created_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="created_pipeline", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="modified_pipeline", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "workflow", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="pipeline_workflows", + to="workflow.workflow", + ), + ), + ], + ), + migrations.AddConstraint( + model_name="pipeline", + constraint=models.UniqueConstraint( + fields=("id", "pipeline_type"), name="unique_pipeline" + ), + ), + ] diff --git a/backend/pipeline/migrations/__init__.py b/backend/pipeline/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/pipeline/models.py b/backend/pipeline/models.py new file mode 100644 index 000000000..2b83b2623 --- /dev/null +++ b/backend/pipeline/models.py @@ -0,0 +1,93 @@ +import uuid + +from account.models import User +from backend.constants import FieldLengthConstants as FieldLength +from django.db import models +from utils.models.base_model import BaseModel +from workflow_manager.workflow.models.workflow import Workflow + +APP_ID_LENGTH = 32 +PIPELINE_NAME_LENGTH = 32 + + +class Pipeline(BaseModel): + """Model to hold data related to Pipelines.""" + + class PipelineType(models.TextChoices): + ETL = "ETL", "ETL" + TASK = "TASK", "TASK" + DEFAULT = "DEFAULT", "Default" + APP = "APP", "App" + + class PipelineStatus(models.TextChoices): + SUCCESS = "SUCCESS", "Success" + FAILURE = "FAILURE", "Failure" + INPROGRESS = "INPROGRESS", "Inprogress" + YET_TO_START = "YET_TO_START", "Yet to start" + RESTARTING = "RESTARTING", "Restarting" + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + pipeline_name = models.CharField( + max_length=PIPELINE_NAME_LENGTH, default="", unique=True + ) + workflow = models.ForeignKey( + Workflow, + on_delete=models.CASCADE, + related_name="pipeline_workflows", + null=False, + blank=False, + ) + # Added as text field until a model for App is included. + app_id = models.TextField(null=True, blank=True, max_length=APP_ID_LENGTH) + active = models.BooleanField(default=False) # TODO: Add dbcomment + scheduled = models.BooleanField(default=False) # TODO: Add dbcomment + cron_string = models.TextField( + db_comment="UNIX cron string", + null=False, + blank=False, + max_length=FieldLength.CRON_LENGTH, + ) + pipeline_type = models.CharField( + choices=PipelineType.choices, default=PipelineType.DEFAULT + ) + run_count = models.IntegerField(default=0) + last_run_time = models.DateTimeField(null=True, blank=True) + last_run_status = models.CharField( + choices=PipelineStatus.choices, default=PipelineStatus.YET_TO_START + ) + app_icon = models.URLField( + null=True, blank=True, db_comment="Field to store icon url for Apps" + ) + app_url = models.URLField( + null=True, blank=True, db_comment="Stores deployed URL for App" + ) + # TODO: Change this to a Forgein key once the bundle is created. + access_control_bundle_id = models.TextField(null=True, blank=True) + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="created_pipeline", + null=True, + blank=True, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="modified_pipeline", + null=True, + blank=True, + ) + + def __str__(self) -> str: + return f"Pipeline({self.id})" + + class Meta: + constraints = [ + models.UniqueConstraint( + fields=["id", "pipeline_type"], + name="unique_pipeline", + ), + ] + + def is_active(self) -> bool: + return bool(self.active) diff --git a/backend/pipeline/pipeline_processor.py b/backend/pipeline/pipeline_processor.py new file mode 100644 index 000000000..740034625 --- /dev/null +++ b/backend/pipeline/pipeline_processor.py @@ -0,0 +1,61 @@ +import logging + +from django.utils import timezone +from pipeline.exceptions import InactivePipelineError, PipelineSaveError +from pipeline.models import Pipeline + +logger = logging.getLogger(__name__) + + +class PipelineProcessor: + @staticmethod + def initialize_pipeline_sync(pipeline_id: str) -> Pipeline: + """Fetches and initializes the sync for a pipeline. + + Args: + pipeline_id (str): UUID of the pipeline to sync + """ + pipeline: Pipeline = PipelineProcessor.fetch_pipeline(pipeline_id) + pipeline.run_count = pipeline.run_count + 1 + return PipelineProcessor.update_pipeline_status( + pipeline=pipeline, + status=Pipeline.PipelineStatus.RESTARTING, + is_end=False, + ) + + @staticmethod + def fetch_pipeline(pipeline_id: str, check_active: bool = True) -> Pipeline: + """Retrieves and checks for an active pipeline. + + Raises: + InactivePipelineError: If an active pipeline is not found + """ + pipeline: Pipeline = Pipeline.objects.get(pk=pipeline_id) + if check_active and not pipeline.is_active(): + logger.error(f"Inactive pipeline fetched: {pipeline_id}") + raise InactivePipelineError + return pipeline + + @staticmethod + def update_pipeline_status( + pipeline: Pipeline, status: tuple[str, str], is_end: bool + ) -> Pipeline: + """Updates pipeline status during execution. + + Raises: + PipelineSaveError: Exception while saving a pipeline + + Returns: + Pipeline: Updated pipeline + """ + if is_end: + pipeline.last_run_time = timezone.now() + if status: + pipeline.last_run_status = status + + try: + pipeline.save() + except Exception as exc: + logger.error(f"Error occured while saving pipeline : {exc}") + raise PipelineSaveError() + return pipeline diff --git a/backend/pipeline/serializers/crud.py b/backend/pipeline/serializers/crud.py new file mode 100644 index 000000000..a42dd63a3 --- /dev/null +++ b/backend/pipeline/serializers/crud.py @@ -0,0 +1,114 @@ +import logging +from collections import OrderedDict +from typing import Any + +from backend.serializers import AuditSerializer +from connector.models import ConnectorInstance +from connector_processor.connector_processor import ConnectorProcessor +from cron_expression_generator.constants import CronKeys +from cron_expression_generator.descriptor import CronDescriptor +from cron_expression_generator.exceptions import CronDescriptionError +from pipeline.constants import PipelineConstants as PC +from pipeline.constants import PipelineKey as PK +from pipeline.models import Pipeline +from rest_framework.exceptions import ValidationError +from rest_framework.serializers import UUIDField +from scheduler.helper import SchedulerHelper +from tool_instance.serializers import ToolInstanceSerializer +from tool_instance.tool_instance_helper import ToolInstanceHelper +from utils.serializer_utils import SerializerUtils +from workflow_manager.workflow.constants import WorkflowKey + +logger = logging.getLogger(__name__) + + +class PipelineSerializer(AuditSerializer): + workflow_id = UUIDField(write_only=True) + + class Meta: + model = Pipeline + fields = "__all__" + extra_kwargs = { + PK.WORKFLOW: { + "required": False, + }, + } + + def to_internal_value(self, data: dict[str, str]) -> OrderedDict[str, str]: + if WorkflowKey.WF_ID in data: + data[PK.WORKFLOW] = data[WorkflowKey.WF_ID] + return super().to_internal_value(data) # type: ignore + + def create(self, validated_data: dict[str, Any]) -> Any: + # TODO: Deduce pipeline type based on WF? + validated_data[PK.ACTIVE] = True # Add this as default instead? + validated_data[PK.SCHEDULED] = True + return super().create(validated_data) + + def save(self, **kwargs: Any) -> Pipeline: + pipeline: Pipeline = super().save(**kwargs) + SchedulerHelper.add_job( + str(pipeline.pk), + cron_string=pipeline.cron_string, + ) + return pipeline + + def validate_cron_string(self, value: str) -> str: + try: + CronDescriptor.describe_cron(value) + except CronDescriptionError: + raise ValidationError("Cron schedule is of invalid format") + return value + + def _add_cron_summary( + self, repr: OrderedDict[str, Any] + ) -> OrderedDict[str, Any]: + """Adds cron_summary in place if cron_string is present as a separate + JSON. + + Args: + repr (OrderedDict[str, Any]): Dict that has to be returned to + the user + + Returns: + OrderedDict[str, Any]: repr with the cron string and its summary + """ + cron_string = repr.pop(CronKeys.CRON_STRING) + if cron_string: + repr[PK.CRON_DATA] = { + CronKeys.CRON_STRING: cron_string, + PK.CRON_SUMMARY: CronDescriptor.describe_cron(cron_string), + } + return repr + + def to_representation(self, instance: Pipeline) -> OrderedDict[str, Any]: + """To set Source, Destination & Agency for Pipelines.""" + repr: OrderedDict[str, Any] = super().to_representation(instance) + + if SerializerUtils.check_context_for_GET_or_POST(context=self.context): + workflow = instance.workflow + tool_instances = ToolInstanceSerializer( + instance=ToolInstanceHelper.get_tool_instances_by_workflow( + workflow_id=instance.workflow_id, order_by="step" + ), + many=True, + context=self.context, + ).data + repr[PK.WORKFLOW_ID] = workflow.id + repr[PK.WORKFLOW_NAME] = workflow.workflow_name + repr = self._add_cron_summary(repr=repr) + + if not tool_instances: + repr[PC.SOURCE_NAME] = PC.SOURCE_NOT_CONFIGURED + repr[PC.DESTINATION_NAME] = PC.DESTINATION_NOT_CONFIGURED + return repr + + # TODO: Change here to handle pipeline src/dest based on WF + repr[PC.DESTINATION_NAME] = PC.NOT_CONFIGURED + + return repr + + def get_connector_data(self, connector: ConnectorInstance, key: str) -> Any: + return ConnectorProcessor.get_connector_data_with_key( + connector.connector_id, key + ) diff --git a/backend/pipeline/serializers/execute.py b/backend/pipeline/serializers/execute.py new file mode 100644 index 000000000..88b57e199 --- /dev/null +++ b/backend/pipeline/serializers/execute.py @@ -0,0 +1,19 @@ +import logging + +from pipeline.models import Pipeline +from rest_framework import serializers + +logger = logging.getLogger(__name__) + + +class PipelineExecuteSerializer(serializers.Serializer): + # TODO: Add pipeline as a read_only related field + pipeline_id = serializers.UUIDField() + execution_id = serializers.UUIDField(required=False) + + def validate_pipeline_id(self, value: str) -> str: + try: + Pipeline.objects.get(pk=value) + except Pipeline.DoesNotExist: + raise serializers.ValidationError("Invalid pipeline ID") + return value diff --git a/backend/pipeline/static/etl_pipelines.json b/backend/pipeline/static/etl_pipelines.json new file mode 100644 index 000000000..6ef870d7c --- /dev/null +++ b/backend/pipeline/static/etl_pipelines.json @@ -0,0 +1,62 @@ +[ + { + "pipeline_id": 1, + "pipeline_type": "UNSTRUCTURED_TO_STRUCTURED", + "source": "Google Drive", + "source_icon": "https://storage.googleapis.com/pandora-static/connector-icons/Google%20Drive.png", + "workflow": { + "id": 1, + "name": "Resume parsing workflow" + }, + "destination": "Snowflake", + "destination_icon": "https://storage.googleapis.com/pandora-static/connector-icons/Snowflake.png", + "schedule": "Every 12 hours", + "last_run": "2023-07-05 12:00:00", + "enabled": true + }, + { + "pipeline_id": 2, + "pipeline_type": "UNSTRUCTURED_TO_STRUCTURED", + "source": "Dropbox", + "source_icon": "https://storage.googleapis.com/pandora-static/connector-icons/Dropbox.png", + "workflow": { + "id": 2, + "name": "Invoice parsing workflow" + }, + "destination": "Snowflake", + "destination_icon": "https://storage.googleapis.com/pandora-static/connector-icons/Snowflake.png", + "schedule": "Every 6 hours", + "last_run": "2023-07-04 16:00:00", + "enabled": true + }, + { + "pipeline_id": 3, + "pipeline_type": "UNSTRUCTURED_TO_STRUCTURED", + "source": "Unstract Storage", + "source_icon": "https://storage.googleapis.com/pandora-static/connector-icons/Pandora%20Storage.png", + "workflow": { + "id": 3, + "name": "Contract parsing workflow" + }, + "destination": "Snowflake", + "destination_icon": "https://storage.googleapis.com/pandora-static/connector-icons/Snowflake.png", + "schedule": "Once Every Day", + "last_run": "2023-07-05 00:00:00", + "enabled": false + }, + { + "pipeline_id": 4, + "pipeline_type": "UNSTRUCTURED_TO_STRUCTURED", + "source": "Google Drive", + "source_icon": "https://storage.googleapis.com/pandora-static/connector-icons/Google%20Drive.png", + "workflow": { + "id": 4, + "name": "Contract parsing workflow" + }, + "destination": "BigQuery", + "destination_icon": "https://storage.googleapis.com/pandora-static/connector-icons/google_bigquery-icon.svg", + "schedule": "Every 6 hours", + "last_run": "2023-07-05 12:00:00", + "enabled": true + } +] diff --git a/backend/pipeline/static/task_pipelines.json b/backend/pipeline/static/task_pipelines.json new file mode 100644 index 000000000..d266a5aed --- /dev/null +++ b/backend/pipeline/static/task_pipelines.json @@ -0,0 +1,47 @@ +[ + { + "pipeline_id": 1, + "pipeline_type": "TASK_PIPELINE", + "source": "Google Drive", + "source_icon": "https://storage.googleapis.com/pandora-static/connector-icons/Google%20Drive.png", + "workflow": { + "id": 1, + "name": "PII Redaction workflow" + }, + "destination": "Google Drive", + "destination_icon": "https://storage.googleapis.com/pandora-static/connector-icons/Google%20Drive.png", + "schedule": "Every 4 hours", + "last_run": "2023-07-05 17:00:00", + "enabled": true + }, + { + "pipeline_id": 2, + "pipeline_type": "TASK_PIPELINE", + "source": "Dropbox", + "source_icon": "https://storage.googleapis.com/pandora-static/connector-icons/Dropbox.png", + "workflow": { + "id": 2, + "name": "Document classification workflow" + }, + "destination": "Google Drive", + "destination_icon": "https://storage.googleapis.com/pandora-static/connector-icons/Google%20Drive.png", + "schedule": "Every 9 hours", + "last_run": "2023-07-04 21:00:00", + "enabled": false + }, + { + "pipeline_id": 3, + "pipeline_type": "TASK_PIPELINE", + "source": "Unstract Storage", + "source_icon": "https://storage.googleapis.com/pandora-static/connector-icons/Pandora%20Storage.png", + "workflow": { + "id": 3, + "name": "Document translation workflow" + }, + "destination": "Unstract Storage", + "destination_icon": "https://storage.googleapis.com/pandora-static/connector-icons/Pandora%20Storage.png", + "schedule": "Once Every Day", + "last_run": "2023-07-05 00:00:00", + "enabled": false + } +] diff --git a/backend/pipeline/urls.py b/backend/pipeline/urls.py new file mode 100644 index 000000000..9f2de2792 --- /dev/null +++ b/backend/pipeline/urls.py @@ -0,0 +1,25 @@ +from django.urls import path +from pipeline.constants import PipelineURL +from pipeline.views import PipelineViewSet +from rest_framework.urlpatterns import format_suffix_patterns + +pipeline_list = PipelineViewSet.as_view( + { + "get": "list", + "post": "create", + } +) +pipeline_detail = PipelineViewSet.as_view( + {"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"} +) + +pipeline_execute = PipelineViewSet.as_view({"post": "execute"}) + + +urlpatterns = format_suffix_patterns( + [ + path("pipeline/", pipeline_list, name=PipelineURL.LIST), + path("pipeline//", pipeline_detail, name=PipelineURL.DETAIL), + path("pipeline/execute/", pipeline_execute, name=PipelineURL.EXECUTE), + ] +) diff --git a/backend/pipeline/views.py b/backend/pipeline/views.py new file mode 100644 index 000000000..91e73ce4d --- /dev/null +++ b/backend/pipeline/views.py @@ -0,0 +1,120 @@ +import logging +from typing import Optional + +from account.custom_exceptions import DuplicateData +from cron_expression_generator.constants import CronKeys +from django.db import IntegrityError +from django.db.models import QuerySet +from drf_yasg import openapi +from drf_yasg.utils import swagger_auto_schema +from permissions.permission import IsOwner +from pipeline.constants import ( + PipelineConstants, + PipelineErrors, + PipelineExecutionKey, +) +from pipeline.constants import PipelineKey as PK +from pipeline.exceptions import MandatoryCronSchedule, MandatoryWorkflowId +from pipeline.manager import PipelineManager +from pipeline.models import Pipeline +from pipeline.pipeline_processor import PipelineProcessor +from pipeline.serializers.crud import PipelineSerializer +from pipeline.serializers.execute import ( + PipelineExecuteSerializer as ExecuteSerializer, +) +from rest_framework import serializers, status, viewsets +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning +from scheduler.helper import SchedulerHelper +from workflow_manager.workflow.constants import ( + WorkflowExecutionKey as WFExecKey, +) +from workflow_manager.workflow.constants import WorkflowKey + +logger = logging.getLogger(__name__) + + +class PipelineViewSet(viewsets.ModelViewSet): + versioning_class = URLPathVersioning + queryset = Pipeline.objects.all() + permission_classes = [IsOwner] + serializer_class = PipelineSerializer + + # For doc strings + with_log = openapi.Parameter( + "with_log", + openapi.IN_QUERY, + description="To pass workflow execution logs to FE", + type=openapi.TYPE_BOOLEAN, + enum=[True, False], + ) + + def get_queryset(self) -> Optional[QuerySet]: + type = self.request.query_params.get(PipelineConstants.TYPE) + if type is not None: + queryset = Pipeline.objects.filter( + created_by=self.request.user, pipeline_type=type + ) + return queryset + elif type is None: + queryset = Pipeline.objects.filter(created_by=self.request.user) + return queryset + + def get_serializer_class(self) -> serializers.Serializer: + if self.action == "execute": + return ExecuteSerializer + else: + return PipelineSerializer + + # TODO: Refactor to perform an action with explicit arguments + # For eg, passing pipeline ID and with_log=False -> executes pipeline + # For FE however we call the same API twice + # (first call generates execution ID) + @swagger_auto_schema(manual_parameters=[with_log]) + def execute(self, request: Request) -> Response: + # TODO: Use a serializer instead to validate args + with_log = request.query_params.get(WFExecKey.WITH_LOG) + serializer: ExecuteSerializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + execution_id = serializer.validated_data.get("execution_id", None) + pipeline_id = serializer.validated_data[PK.PIPELINE_ID] + + execution = PipelineManager.execute_pipeline( + request=request, + pipeline_id=pipeline_id, + execution_id=execution_id, + with_log=with_log, + ) + pipeline: Pipeline = PipelineProcessor.fetch_pipeline(pipeline_id) + serializer = PipelineSerializer(pipeline) + response_data = { + PipelineExecutionKey.PIPELINE: serializer.data, + PipelineExecutionKey.EXECUTION: execution.data, + } + return Response(data=response_data, status=status.HTTP_200_OK) + + def create(self, request: Request) -> Response: + workflow_id = request.data.get(WorkflowKey.WF_ID) + cron_string = request.data.get(CronKeys.CRON_STRING) + # TODO: Remove these checks once ValidationError is handled properly + if not workflow_id: + raise MandatoryWorkflowId() + if not cron_string: + raise MandatoryCronSchedule() + + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + try: + serializer.save() + except IntegrityError: + raise DuplicateData( + f"{PipelineErrors.PIPELINE_EXISTS}, " + f"{PipelineErrors.DUPLICATE_API}" + ) + return Response(data=serializer.data, status=status.HTTP_201_CREATED) + + def perform_destroy(self, instance: Pipeline) -> None: + pipeline_to_remove = str(instance.pk) + super().perform_destroy(instance) + return SchedulerHelper.remove_job(pipeline_to_remove) diff --git a/backend/platform_settings/__init__.py b/backend/platform_settings/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/platform_settings/admin.py b/backend/platform_settings/admin.py new file mode 100644 index 000000000..846f6b406 --- /dev/null +++ b/backend/platform_settings/admin.py @@ -0,0 +1 @@ +# Register your models here. diff --git a/backend/platform_settings/apps.py b/backend/platform_settings/apps.py new file mode 100644 index 000000000..1ecd0f245 --- /dev/null +++ b/backend/platform_settings/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class PlatformSettingsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "platform_settings" diff --git a/backend/platform_settings/constants.py b/backend/platform_settings/constants.py new file mode 100644 index 000000000..29ba63684 --- /dev/null +++ b/backend/platform_settings/constants.py @@ -0,0 +1,14 @@ +class PlatformServiceConstants: + IS_ACTIVE = "is_active" + KEY = "key" + ORGANIZATION = "organization" + ID = "id" + ACTIVATE = "ACTIVATE" + DEACTIVATE = "DEACTIVATE" + ACTION = "action" + KEY_NAME = "key_name" + + +class ErrorMessage: + KEY_EXIST = "Key name already exists" + DUPLICATE_API = "It appears that a duplicate call may have been made." diff --git a/backend/platform_settings/exceptions.py b/backend/platform_settings/exceptions.py new file mode 100644 index 000000000..e591ae5ca --- /dev/null +++ b/backend/platform_settings/exceptions.py @@ -0,0 +1,46 @@ +from typing import Optional + +from rest_framework.exceptions import APIException + + +class InternalServiceError(APIException): + status_code = 500 + default_detail = "Internal error occurred while platform key operations." + + +class UserForbidden(APIException): + status_code = 403 + default_detail = ( + "User is forbidden from performing this action. Please contact admin" + ) + + +class KeyCountExceeded(APIException): + status_code = 403 + default_detail = ( + "Maximum key count is exceeded. Please delete one before generation." + ) + + +class FoundActiveKey(APIException): + status_code = 403 + default_detail = "Only one active key allowed at a time." + + +class ActiveKeyNotFound(APIException): + status_code = 404 + default_detail = "At least one active platform key should be available" + + +class DuplicateData(APIException): + status_code = 400 + default_detail = "Duplicate Data" + + def __init__( + self, detail: Optional[str] = None, code: Optional[int] = None + ): + if detail is not None: + self.detail = detail + if code is not None: + self.code = code + super().__init__(detail, code) diff --git a/backend/platform_settings/migrations/__init__.py b/backend/platform_settings/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/platform_settings/models.py b/backend/platform_settings/models.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/platform_settings/platform_auth_helper.py b/backend/platform_settings/platform_auth_helper.py new file mode 100644 index 000000000..c3d7d2d4b --- /dev/null +++ b/backend/platform_settings/platform_auth_helper.py @@ -0,0 +1,51 @@ +import logging + +from account.authentication_controller import AuthenticationController +from account.models import Organization, PlatformKey, User +from platform_settings.exceptions import KeyCountExceeded, UserForbidden +from tenant_account.models import OrganizationMember + +PLATFORM_KEY_COUNT = 2 + +logger = logging.getLogger(__name__) + + +class PlatformAuthHelper: + """Class to hold helper functions for Platform settings authentication.""" + + @staticmethod + def validate_user_role(user: User) -> None: + """This method validates if the logged in user has admin role for + performing appropriate actions. + + Args: + user (User): Logged in user from context + """ + auth_controller = AuthenticationController() + try: + member: OrganizationMember = ( + auth_controller.get_organization_members_by_user(user=user) + ) + except Exception as error: + logger.error( + f"Error occurred while fetching organization for user : {error}" + ) + raise error + if not auth_controller.is_admin_by_role(member.role): + logger.error("User is not having right access to perform this operation.") + raise UserForbidden() + else: + pass + + @staticmethod + def validate_token_count(organization: Organization) -> None: + if ( + PlatformKey.objects.filter(organization=organization).count() + >= PLATFORM_KEY_COUNT + ): + logger.error( + f"Only {PLATFORM_KEY_COUNT} keys are support at a time. Count exceeded." + ) + raise KeyCountExceeded() + else: + pass diff --git a/backend/platform_settings/platform_auth_service.py b/backend/platform_settings/platform_auth_service.py new file mode 100644 index 000000000..8ad74b20e --- /dev/null +++ b/backend/platform_settings/platform_auth_service.py @@ -0,0 +1,234 @@ +import logging +import uuid +from typing import Any, Optional + +from account.models import Organization, PlatformKey, User +from django.db import IntegrityError, connection +from django_tenants.utils import get_tenant_model +from platform_settings.exceptions import ( + ActiveKeyNotFound, + DuplicateData, + InternalServiceError, +) +from tenant_account.constants import ErrorMessage, PlatformServiceConstants + +logger = logging.getLogger(__name__) + + +class PlatformAuthenticationService: + """Service class to hold Platform service authentication and validation. + + Supports generation, refresh, revoke and toggle of active keys. + """ + + @staticmethod + def generate_platform_key( + is_active: bool, key_name: str, user: User + ) -> dict[str, Any]: + """Method to support generation of new platform key. Throws error when + maximum count is exceeded. Forbids for user other than admin + permission. + + Args: + key (str): Value of the key + is_active (bool): By default the key is False + organization_id (str): Org the key belongs to. + + Returns: + PlatformKey + """ + organization = connection.get_tenant() + try: + # TODO : Add encryption to Platform keys + # id is added here to avoid passing of keys in transactions. + platform_key: PlatformKey = PlatformKey( + id=str(uuid.uuid4()), + key=str(uuid.uuid4()), + is_active=is_active, + organization=organization, + key_name=key_name, + created_by=user, + modified_by=user, + ) + platform_key.save() + result: dict[str, Any] = {} + result[PlatformServiceConstants.ID] = platform_key.id + result[PlatformServiceConstants.KEY_NAME] = platform_key.key_name + result[PlatformServiceConstants.KEY] = platform_key.key + + logger.info(f"platform_key is generated for {organization.id}") + return result + except IntegrityError as error: + logger.error( + f"Integrity error - failed to generate platform key : {error}" + ) + raise DuplicateData( + f"{ErrorMessage.KEY_EXIST}, \ + {ErrorMessage.DUPLICATE_API}" + ) + except Exception as error: + logger.error(f"Failed to generate platform key : {error}") + raise InternalServiceError() + + @staticmethod + def delete_platform_key(id: str) -> None: + """This is a delete operation. Use this function only if you know what + you are doing. + + Args: + id (str): _description_ + + Raises: + error: _description_ + """ + try: + platform_key: PlatformKey = PlatformKey.objects.get(pk=id) + platform_key.delete() + logger.info(f"platform_key {id} is deleted") + except IntegrityError as error: + logger.error(f"Failed to delete platform key : {error}") + raise DuplicateData( + f"{ErrorMessage.KEY_EXIST}, \ + {ErrorMessage.DUPLICATE_API}" + ) + except Exception as error: + logger.error(f"Failed to delete platform key : {error}") + raise InternalServiceError() + + @staticmethod + def refresh_platform_key(id: str, user: User) -> dict[str, Any]: + """Method to refresh a platform key. + + Args: + id (str): Unique id of the key to be refreshed + new_key (str): Value to be updated. + + Raises: + error: IntegrityError + """ + try: + result: dict[str, Any] = {} + platform_key: PlatformKey = PlatformKey.objects.get(pk=id) + platform_key.key = str(uuid.uuid4()) + platform_key.modified_by = user + platform_key.save() + result[PlatformServiceConstants.ID] = platform_key.id + result[PlatformServiceConstants.KEY_NAME] = platform_key.key_name + result[PlatformServiceConstants.KEY] = platform_key.key + + logger.info(f"platform_key {id} is updated by user {user.id}") + return result + except IntegrityError as error: + logger.error( + f"Integrity error - failed to refresh platform key : {error}" + ) + raise DuplicateData( + f"{ErrorMessage.KEY_EXIST}, \ + {ErrorMessage.DUPLICATE_API}" + ) + except Exception as error: + logger.error(f"Failed to refresh platform key : {error}") + raise InternalServiceError() + + @staticmethod + def toggle_platform_key_status( + platform_key: PlatformKey, action: str, user: User + ) -> None: + """Method to activate/deactivate a platform key. Only one active key is + allowed at a time. On change or setting, other keys are deactivated. + + Args: + id (str): Id of the key to be toggled. + action (str): activate/deactivate + + Raises: + error: IntegrityError + """ + try: + organization = connection.get_tenant() + platform_key.modified_by = user + if action == PlatformServiceConstants.ACTIVATE: + active_keys: list[PlatformKey] = PlatformKey.objects.filter( + is_active=True, organization=organization + ).all() + # Deactivates all keys + for key in active_keys: + key.is_active = False + key.modified_by = user + key.save() + # Activates the chosen key. + platform_key.is_active = True + platform_key.save() + if action == PlatformServiceConstants.DEACTIVATE: + platform_key.is_active = False + platform_key.save() + except IntegrityError as error: + logger.error( + "IntegrityError - Failed to activate/deactivate " + f"platform key : {error}" + ) + raise DuplicateData( + f"{ErrorMessage.KEY_EXIST}, \ + {ErrorMessage.DUPLICATE_API}" + ) + except Exception as error: + logger.error( + f"Failed to activate/deactivate platform key : {error}" + ) + raise InternalServiceError() + + @staticmethod + def list_platform_key_ids() -> list[PlatformKey]: + """Method to fetch list of platform keys unique ids for internal usage. + + Returns: + Any: List of platform keys. + """ + try: + organization_id = connection.get_tenant().id + platform_keys: list[PlatformKey] = PlatformKey.objects.filter( + organization=organization_id + ) + return platform_keys + except Exception as error: + logger.error(f"Failed to fetch platform key ids : {error}") + raise InternalServiceError() + + @staticmethod + def fetch_platform_key_id() -> Any: + """Method to fetch list of platform keys unique ids for internal usage. + + Returns: + Any: List of platform keys. + """ + try: + platform_key: list[PlatformKey] = PlatformKey.objects.all() + return platform_key + except Exception as error: + logger.error(f"Failed to fetch platform key ids : {error}") + raise InternalServiceError() + + @staticmethod + def get_active_platform_key( + organization_id: Optional[str] = None, + ) -> PlatformKey: + """Method to fetch active key. + + Considering only one active key is allowed at a time + Returns: + Any: platformKey. + """ + try: + organization_id = organization_id or connection.tenant.schema_name + organization: Organization = get_tenant_model().objects.get( + schema_name=organization_id + ) + platform_key: PlatformKey = PlatformKey.objects.get( + organization=organization, is_active=True + ) + return platform_key + except PlatformKey.DoesNotExist: + raise ActiveKeyNotFound() + except Exception as error: + logger.error(f"Failed to fetch platform key : {error}") + raise InternalServiceError() diff --git a/backend/platform_settings/serializers.py b/backend/platform_settings/serializers.py new file mode 100644 index 000000000..f8e320e18 --- /dev/null +++ b/backend/platform_settings/serializers.py @@ -0,0 +1,25 @@ +# serializers.py + +from account.models import PlatformKey +from backend.serializers import AuditSerializer +from rest_framework import serializers + + +class PlatformKeySerializer(AuditSerializer): + class Meta: + model = PlatformKey + fields = "__all__" + + +class PlatformKeyGenerateSerializer(serializers.Serializer): + # Adjust these fields based on your actual serializer + is_active = serializers.BooleanField() + + key_name = serializers.CharField() + + +class PlatformKeyIDSerializer(serializers.Serializer): + id = serializers.CharField() + key_name = serializers.CharField() + key = serializers.CharField() + is_active = serializers.BooleanField() diff --git a/backend/platform_settings/tests.py b/backend/platform_settings/tests.py new file mode 100644 index 000000000..a39b155ac --- /dev/null +++ b/backend/platform_settings/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/backend/platform_settings/urls.py b/backend/platform_settings/urls.py new file mode 100644 index 000000000..feb1f5cc1 --- /dev/null +++ b/backend/platform_settings/urls.py @@ -0,0 +1,26 @@ +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns + +from .views import PlatformKeyViewSet + +platform_key_list = PlatformKeyViewSet.as_view( + {"post": "create", "put": "refresh", "get": "list"} +) +platform_key_update = PlatformKeyViewSet.as_view( + {"put": "toggle_platform_key", "delete": "destroy"} +) + +urlpatterns = format_suffix_patterns( + [ + path( + "keys/", + platform_key_list, + name="generate_platform_key", + ), + path( + "keys//", + platform_key_update, + name="update_platform_key", + ), + ] +) diff --git a/backend/platform_settings/views.py b/backend/platform_settings/views.py new file mode 100644 index 000000000..ace584262 --- /dev/null +++ b/backend/platform_settings/views.py @@ -0,0 +1,125 @@ +# views.py + +import logging +from typing import Any + +from account.models import Organization, PlatformKey +from django.db import connection +from platform_settings.constants import PlatformServiceConstants +from platform_settings.platform_auth_helper import PlatformAuthHelper +from platform_settings.platform_auth_service import ( + PlatformAuthenticationService, +) +from platform_settings.serializers import ( + PlatformKeyGenerateSerializer, + PlatformKeyIDSerializer, + PlatformKeySerializer, +) +from rest_framework import status, viewsets +from rest_framework.request import Request +from rest_framework.response import Response + +logger = logging.getLogger(__name__) + + +class PlatformKeyViewSet(viewsets.ModelViewSet): + queryset = PlatformKey.objects.all() + serializer_class = PlatformKeySerializer + + def validate_user_role(func: Any) -> Any: + def wrapper( + self: Any, + request: Request, + *args: tuple[Any], + **kwargs: dict[str, Any], + ) -> Any: + PlatformAuthHelper.validate_user_role(request.user) + return func(self, request, *args, **kwargs) + + return wrapper + + @validate_user_role + def list( + self, request: Request, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> Response: + platform_key_ids = PlatformAuthenticationService.list_platform_key_ids() + serializer = PlatformKeyIDSerializer(platform_key_ids, many=True) + return Response( + status=status.HTTP_200_OK, + data=serializer.data, + ) + + @validate_user_role + def refresh( + self, request: Request, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> Response: + """API Endpoint for refreshing platform keys.""" + id = request.data.get(PlatformServiceConstants.ID) + if not id: + return Response( + status=status.HTTP_400_BAD_REQUEST, + data={ + "message": "validation error", + "errors": "Mandatory fields missing", + }, + ) + platform_key = PlatformAuthenticationService.refresh_platform_key( + id=id, user=request.user + ) + return Response( + status=status.HTTP_201_CREATED, + data=platform_key, + ) + + @validate_user_role + def destroy( + self, request: Request, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> Response: + instance = self.get_object() + instance.delete() + return Response( + status=status.HTTP_204_NO_CONTENT, + data={"message": "Platform key deleted successfully"}, + ) + + @validate_user_role + def toggle_platform_key( + self, request: Request, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> Response: + instance = self.get_object() + action = request.data.get(PlatformServiceConstants.ACTION) + if not action: + return Response( + status=status.HTTP_400_BAD_REQUEST, + data={ + "message": "validation error", + "errors": "Mandatory fields missing", + }, + ) + PlatformAuthenticationService.toggle_platform_key_status( + platform_key=instance, action=action, user=request.user + ) + return Response( + status=status.HTTP_201_CREATED, + data={"message": "Platform key toggled successfully"}, + ) + + @validate_user_role + def create(self, request: Request) -> Response: + serializer = PlatformKeyGenerateSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + is_active = request.data.get(PlatformServiceConstants.IS_ACTIVE) + key_name = request.data.get(PlatformServiceConstants.KEY_NAME) + + organization: Organization = connection.get_tenant() + + PlatformAuthHelper.validate_token_count(organization=organization) + + platform_key = PlatformAuthenticationService.generate_platform_key( + is_active=is_active, key_name=key_name, user=request.user + ) + serialized_data = self.serializer_class(platform_key).data + return Response( + status=status.HTTP_201_CREATED, + data=serialized_data, + ) diff --git a/backend/plugins/README.md b/backend/plugins/README.md new file mode 100644 index 000000000..b03ee2c78 --- /dev/null +++ b/backend/plugins/README.md @@ -0,0 +1,5 @@ +# Plugins + +## Authentication + +Enhance the authentication capabilities of the `account/authentication_controller.py` module by incorporating additional modules. diff --git a/backend/plugins/__init__.py b/backend/plugins/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/plugins/authentication/auth_sample/__init__.py b/backend/plugins/authentication/auth_sample/__init__.py new file mode 100644 index 000000000..1698e4b3e --- /dev/null +++ b/backend/plugins/authentication/auth_sample/__init__.py @@ -0,0 +1,8 @@ +from .auth_service import AuthService + +metadata = { + "name": "sample_auth", + "service_class": AuthService, + "description": "Sample Authentication Method", + "is_active": False, +} diff --git a/backend/plugins/authentication/auth_sample/auth_helper.py b/backend/plugins/authentication/auth_sample/auth_helper.py new file mode 100644 index 000000000..60cd8217e --- /dev/null +++ b/backend/plugins/authentication/auth_sample/auth_helper.py @@ -0,0 +1,36 @@ +import logging + +from authlib.integrations.django_client import OAuth +from rest_framework.request import Request +from rest_framework.response import Response + +from .dto import TokenData +from .exceptions import MethodNotImplemented + +Logger = logging.getLogger(__name__) + + +class AuthHelper: + def __init__(self) -> None: + self.oauth = OAuth() + + self.oauth.register("auth_project_name") + + def get_authorize_token(self, request: Request) -> TokenData: + return TokenData( + user_id="", + email="", + token="", + ) + + def get_oauth_token(self) -> str: + raise MethodNotImplemented() + + def auth_logout(self, request: Request) -> Response: + raise MethodNotImplemented() + + def clear_custom_cookies(self, response: Response) -> None: + raise MethodNotImplemented() + + def autho_reset_password(self, email: str) -> bool: + raise MethodNotImplemented() diff --git a/backend/plugins/authentication/auth_sample/auth_service.py b/backend/plugins/authentication/auth_sample/auth_service.py new file mode 100644 index 000000000..996ec59f4 --- /dev/null +++ b/backend/plugins/authentication/auth_sample/auth_service.py @@ -0,0 +1,71 @@ +import logging +import uuid +from abc import ABC +from typing import Any, Optional + +from rest_framework.request import Request +from rest_framework.response import Response + +from .auth_helper import AuthHelper +from .dto import AuthOrganization, ResetUserPasswordDto, TokenData, User, UserInfo +from .enums import Region +from .exceptions import MethodNotImplemented + +Logger = logging.getLogger(__name__) + + +class AuthService(ABC): + def __init__(self) -> None: + self.authHelper: AuthHelper = AuthHelper() + + def user_login(self, request: Request, region: Region) -> Any: + raise MethodNotImplemented() + + def user_signup(self, request: Request, region: Region) -> Any: + raise MethodNotImplemented() + + def get_authorize_token(self, request: Request) -> TokenData: + return self.authHelper.get_authorize_token(request) + + def user_organizations( + self, user: User, token: Optional[dict[str, Any]] = None + ) -> list[AuthOrganization]: + raise MethodNotImplemented() + + def get_user_info( + self, user: User, token: Optional[dict[str, Any]] = None + ) -> Optional[UserInfo]: + return UserInfo( + id=user.id, name=user.username, display_name=user.username, email=user.email + ) + + def get_organization_info(self, org_id: str) -> Any: + return None + + def make_organization_and_add_member( + self, + user_id: str, + user_name: str, + organization_name: Optional[str] = None, + display_name: Optional[str] = None, + ) -> Optional[AuthOrganization]: + raise MethodNotImplemented() + + def make_user_organization_name(self) -> str: + return str(uuid.uuid4()) + + def make_user_organization_display_name(self, user_name: str) -> str: + name = f"{user_name}'s" if user_name else "Your" + return f"{name} organization" + + def user_logout(self, request: Request) -> Response: + return self.authHelper.auth_logout(request) + + def get_user_id_from_token(self, token: dict[str, Any]) -> Response: + return token["userinfo"]["sub"] + + def get_organization_members_by_org_id(self, organization_id: str) -> Response: + raise MethodNotImplemented() + + def reset_user_password(self, user: User) -> ResetUserPasswordDto: + raise MethodNotImplemented() diff --git a/backend/plugins/authentication/auth_sample/dto.py b/backend/plugins/authentication/auth_sample/dto.py new file mode 100644 index 000000000..88e9baba6 --- /dev/null +++ b/backend/plugins/authentication/auth_sample/dto.py @@ -0,0 +1,41 @@ +from dataclasses import dataclass +from typing import Any, Optional + + +@dataclass +class ResetUserPasswordDto: + status: bool + message: str + + +@dataclass +class UserInfo: + id: str + name: str + email: str + display_name: Optional[str] = None + family_name: Optional[str] = None + picture: Optional[str] = None + + +@dataclass +class User: + id: str + user_id: str + first_name: str + username: str + email: str + + +@dataclass +class TokenData: + user_id: str + email: str + token: Any + + +@dataclass +class AuthOrganization: + id: str + display_name: str + name: str diff --git a/backend/plugins/authentication/auth_sample/enums.py b/backend/plugins/authentication/auth_sample/enums.py new file mode 100644 index 000000000..2ef7d2c5a --- /dev/null +++ b/backend/plugins/authentication/auth_sample/enums.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class Region(Enum): + US = "US" + EU = "EU" diff --git a/backend/plugins/authentication/auth_sample/exceptions.py b/backend/plugins/authentication/auth_sample/exceptions.py new file mode 100644 index 000000000..a4ccf3e1f --- /dev/null +++ b/backend/plugins/authentication/auth_sample/exceptions.py @@ -0,0 +1,6 @@ +from rest_framework.exceptions import APIException + + +class MethodNotImplemented(APIException): + status_code = 501 + default_detail = "Method Not Implemented" diff --git a/backend/project/__init__.py b/backend/project/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/project/admin.py b/backend/project/admin.py new file mode 100644 index 000000000..badc1bba2 --- /dev/null +++ b/backend/project/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import Project + +admin.site.register(Project) diff --git a/backend/project/apps.py b/backend/project/apps.py new file mode 100644 index 000000000..4836c68a9 --- /dev/null +++ b/backend/project/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ProjectConfig(AppConfig): + name = "project" diff --git a/backend/project/constants.py b/backend/project/constants.py new file mode 100644 index 000000000..a80602e55 --- /dev/null +++ b/backend/project/constants.py @@ -0,0 +1,8 @@ +class ProjectErrors: + SERIALIZATION_FAILED = "Data Serialization Failed." + PROJECT_NAME_EXISTS = "Project already exists" + DUPLICATE_API = "It appears that a duplicate call may have been made." + + +class ProjectKey: + PROJECT_ID = "project_id" diff --git a/backend/project/exceptions.py b/backend/project/exceptions.py new file mode 100644 index 000000000..5955482a3 --- /dev/null +++ b/backend/project/exceptions.py @@ -0,0 +1,6 @@ +from rest_framework.exceptions import APIException + + +class BadRequestException(APIException): + status_code = 400 + default_detail = "Bad Request." diff --git a/backend/project/migrations/0001_initial.py b/backend/project/migrations/0001_initial.py new file mode 100644 index 000000000..084af1737 --- /dev/null +++ b/backend/project/migrations/0001_initial.py @@ -0,0 +1,85 @@ +# Generated by Django 4.2.1 on 2024-01-23 11:18 + +import uuid + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Project", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ("project_name", models.CharField(max_length=128, unique=True)), + ( + "settings", + models.JSONField(db_comment="Project settings", null=True), + ), + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "description", + models.TextField(blank=True, max_length=490, null=True), + ), + ( + "project_status", + models.TextField(blank=True, max_length=128, null=True), + ), + ( + "project_identifier", + models.CharField( + choices=[ + ("ETL", "ETL"), + ("TASK", "TASK"), + ("DEFAULT", "Default"), + ("APP", "App"), + ], + default="DEFAULT", + ), + ), + ( + "created_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="created_projects", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="modified_projects", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + migrations.AddConstraint( + model_name="project", + constraint=models.UniqueConstraint( + fields=("id", "project_name"), name="unique_project_name" + ), + ), + ] diff --git a/backend/project/migrations/__init__.py b/backend/project/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/project/models.py b/backend/project/models.py new file mode 100644 index 000000000..cfa575f9a --- /dev/null +++ b/backend/project/models.py @@ -0,0 +1,59 @@ +import uuid + +from account.models import User +from django.db import models +from utils.models.base_model import BaseModel + +PROJECT_NAME_SIZE = 128 +DESCRIPTION_FIELD_LENGTH = 490 + + +class Project(BaseModel): + """Stores data related to a project created by a :model:`account.User` in + an :model:`account.Org`. + + Every org, project is assumed to be unique + """ + + class ProjectIdentifier(models.TextChoices): + ETL = "ETL", "ETL" + TASK = "TASK", "TASK" + DEFAULT = "DEFAULT", "Default" + APP = "APP", "App" + + project_name = models.CharField(max_length=PROJECT_NAME_SIZE, unique=True) + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="created_projects", + null=True, + blank=True, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="modified_projects", + null=True, + blank=True, + ) + settings = models.JSONField(null=True, db_comment="Project settings") + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + description = models.TextField( + null=True, blank=True, max_length=DESCRIPTION_FIELD_LENGTH + ) + project_status = models.TextField( + null=True, blank=True, max_length=PROJECT_NAME_SIZE + ) + project_identifier = models.CharField( + choices=ProjectIdentifier.choices, default=ProjectIdentifier.DEFAULT + ) + + def __str__(self) -> str: + return f"Projects({self.id}, name: {self.project_name})" + + class Meta: + constraints = [ + models.UniqueConstraint( + fields=["id", "project_name"], name="unique_project_name" + ), + ] diff --git a/backend/project/serializers.py b/backend/project/serializers.py new file mode 100644 index 000000000..dea746763 --- /dev/null +++ b/backend/project/serializers.py @@ -0,0 +1,28 @@ +from typing import Any + +from backend.serializers import AuditSerializer +from project.models import Project +from workflow_manager.workflow.constants import WorkflowKey +from workflow_manager.workflow.serializers import WorkflowSerializer + + +class ProjectSerializer(AuditSerializer): + class Meta: + model = Project + fields = "__all__" + + def to_representation(self, instance: Project) -> dict[str, Any]: + representation: dict[str, str] = super().to_representation(instance) + wf = instance.project_workflow.first() + representation[WorkflowKey.WF_ID] = wf.id if wf else "" + return representation + + def create(self, validated_data: dict[str, Any]) -> Any: + project: Project = super().create(validated_data) + workflow_data = {"project": project.id} + workflow_serializer = WorkflowSerializer( + data=workflow_data, context=self.context + ) + workflow_serializer.is_valid(raise_exception=True) + workflow_serializer.save() + return project diff --git a/backend/project/tests/conftest.py b/backend/project/tests/conftest.py new file mode 100644 index 000000000..0f6c3b970 --- /dev/null +++ b/backend/project/tests/conftest.py @@ -0,0 +1,9 @@ +import pytest +from django.core.management import call_command + + +@pytest.fixture(scope="session") +def django_db_setup(django_db_blocker): # type: ignore + fixtures = ["./project/tests/fixtures/fixtures_0001.json"] + with django_db_blocker.unblock(): + call_command("loaddata", *fixtures) diff --git a/backend/project/tests/fixtures/fixtures_0001.json b/backend/project/tests/fixtures/fixtures_0001.json new file mode 100644 index 000000000..e11768655 --- /dev/null +++ b/backend/project/tests/fixtures/fixtures_0001.json @@ -0,0 +1,51 @@ +[ + { + "model": "account.org", + "pk": 1, + "fields": { + "org_name": "Zipstack", + "created_by": 1, + "modified_by": 1, + "modified_at": "2023-06-14T05:28:47.739Z" + } + }, + { + "model": "account.user", + "pk": 1, + "fields": { + "org": 1, + "email": "johndoe@gmail.com", + "first_name": "John", + "last_name": "Doe", + "is_admin": true, + "created_by": null, + "modified_by": null, + "modified_at": "2023-06-14T05:28:47.744Z" + } + }, + { + "model": "account.user", + "pk": 2, + "fields": { + "org": 1, + "email": "user1@gmail.com", + "first_name": "Ron", + "last_name": "Stone", + "is_admin": false, + "created_by": 1, + "modified_by": 1, + "modified_at": "2023-06-14T05:28:47.750Z" + } + }, + { + "model": "project.project", + "pk": 1, + "fields": { + "org": 1, + "project_name": "Unstract Test", + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z" + } + } +] diff --git a/backend/project/tests/project_tests.py b/backend/project/tests/project_tests.py new file mode 100644 index 000000000..891cbd89f --- /dev/null +++ b/backend/project/tests/project_tests.py @@ -0,0 +1,122 @@ +import pytest +from django.urls import reverse +from project.models import Project +from rest_framework import status +from rest_framework.test import APITestCase + +pytestmark = pytest.mark.django_db + + +@pytest.mark.project +class TestProjects(APITestCase): + def test_projects_list(self) -> None: + """Tests to List the projects.""" + + url = reverse("projects_v1-list") + response = self.client.get(url) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_projects_detail(self) -> None: + """Tests to fetch a project with given pk.""" + + url = reverse("projects_v1-detail", kwargs={"pk": 1}) + response = self.client.get(url) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_projects_detail_not_found(self) -> None: + """Tests for negative case to fetch non exiting key.""" + + url = reverse("projects_v1-detail", kwargs={"pk": 768}) + response = self.client.get(url) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_projects_create(self) -> None: + """Tests to create a new project.""" + + url = reverse("projects_v1-list") + data = { + "org": 1, + "project_name": "Pandora8 Test", + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + } + response = self.client.post(url, data, format="json") + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(Project.objects.count(), 2) + + def test_projects_create_bad_request(self) -> None: + """Tests for negative case to throw error on a wrong access.""" + + url = reverse("projects_v1-list") + data = { + "project_name": "Unstract Test", + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + } + response = self.client.post(url, data, format="json") + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_projects_update(self) -> None: + """Tests to update project.""" + + url = reverse("projects_v1-detail", kwargs={"pk": 1}) + data = { + "org": 1, + "project_name": "Pandora6 Test", + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + } + response = self.client.put(url, data, format="json") + project_name = response.data["project_name"] + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual( + project_name, Project.objects.get(project_name=project_name).project_name + ) + + def test_projects_update_pk(self) -> None: + """Tests the PUT method for 400 error.""" + + url = reverse("projects_v1-detail", kwargs={"pk": 1}) + data = { + "org": 2, + "project_name": "Unstract Test", + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z", + } + response = self.client.put(url, data, format="json") + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_projects_update_field(self) -> None: + """Tests the PATCH method.""" + + url = reverse("projects_v1-detail", kwargs={"pk": 1}) + data = {"project_name": "Unstract Test"} + response = self.client.patch(url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_200_OK) + project_name = response.data["project_name"] + + self.assertEqual( + project_name, Project.objects.get(project_name=project_name).project_name + ) + + def test_projects_delete(self) -> None: + """Tests the DELETE method.""" + + url = reverse("projects_v1-detail", kwargs={"pk": 1}) + response = self.client.delete(url, format="json") + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + + url = reverse("projects_v1-detail", kwargs={"pk": 1}) + response = self.client.get(url) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) diff --git a/backend/project/urls.py b/backend/project/urls.py new file mode 100644 index 000000000..b7805e28f --- /dev/null +++ b/backend/project/urls.py @@ -0,0 +1,27 @@ +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns + +from .views import ProjectViewSet + +project_list = ProjectViewSet.as_view({"get": "list", "post": "create"}) +project_detail = ProjectViewSet.as_view( + {"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"} +) + +project_settings = ProjectViewSet.as_view( + {"get": "project_settings", "put": "project_settings"} +) +project_settings_schema = ProjectViewSet.as_view({"get": "project_settings_schema"}) + +urlpatterns = format_suffix_patterns( + [ + path("projects/", project_list, name="projects-list"), + path("projects//", project_detail, name="projects-detail"), + path("projects//settings/", project_settings, name="project-settings"), + path( + "projects/settings/", + project_settings_schema, + name="project-settings-schema", + ), + ] +) diff --git a/backend/project/views.py b/backend/project/views.py new file mode 100644 index 000000000..a18d69aee --- /dev/null +++ b/backend/project/views.py @@ -0,0 +1,59 @@ +import logging +from typing import Any, Optional + +from account.custom_exceptions import DuplicateData +from connector.connector_instance_helper import ConnectorInstanceHelper +from django.conf import settings +from django.db import IntegrityError +from django.db.models import QuerySet +from django.http import HttpRequest +from project.constants import ProjectErrors +from rest_framework import status, viewsets +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning + +from .models import Project +from .serializers import ProjectSerializer + +logger = logging.getLogger(__name__) + + +class ProjectViewSet(viewsets.ModelViewSet): + versioning_class = URLPathVersioning + queryset = Project.objects.all() + serializer_class = ProjectSerializer + + def get_queryset(self) -> Optional[QuerySet]: + created_by = self.request.query_params.get("created_by") + if created_by is not None: + queryset = Project.objects.filter(created_by=created_by) + return queryset + elif created_by is None: + queryset = Project.objects.all() + return queryset + + def create( + self, request: HttpRequest, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> Response: + serializer = self.get_serializer(data=request.data) + # Overriding default exception behavior + serializer.is_valid(raise_exception=True) + try: + self.perform_create(serializer) + except IntegrityError: + raise DuplicateData( + f"{ProjectErrors.PROJECT_NAME_EXISTS}, " + f"{ProjectErrors.DUPLICATE_API}" + ) + # Access the created instance + created_instance: Project = serializer.instance + + # Enable GCS configurations to create GCS while creating a workflow + if ( + settings.GOOGLE_STORAGE_ACCESS_KEY_ID + and settings.UNSTRACT_FREE_STORAGE_BUCKET_NAME + ): + ConnectorInstanceHelper.create_default_gcs_connector( + created_instance, request.user + ) + return Response(serializer.data, status=status.HTTP_201_CREATED) diff --git a/backend/prompt/__init__.py b/backend/prompt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/prompt/admin.py b/backend/prompt/admin.py new file mode 100644 index 000000000..9de0b12ce --- /dev/null +++ b/backend/prompt/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import Prompt + +admin.site.register(Prompt) diff --git a/backend/prompt/apps.py b/backend/prompt/apps.py new file mode 100644 index 000000000..1c08e89f1 --- /dev/null +++ b/backend/prompt/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class PromptConfig(AppConfig): + name = "prompt" diff --git a/backend/prompt/constants.py b/backend/prompt/constants.py new file mode 100644 index 000000000..4357ffc8d --- /dev/null +++ b/backend/prompt/constants.py @@ -0,0 +1,3 @@ +class PromptErrors: + PROMPT_EXISTS = "Prompt with this configuration already exists" + DUPLICATE_API = "It appears that a duplicate call may have been made." diff --git a/backend/prompt/migrations/0001_initial.py b/backend/prompt/migrations/0001_initial.py new file mode 100644 index 000000000..7b00ca293 --- /dev/null +++ b/backend/prompt/migrations/0001_initial.py @@ -0,0 +1,73 @@ +# Generated by Django 4.2.1 on 2024-01-23 11:18 + +import uuid + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("project", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="Prompt", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ("version_name", models.CharField(max_length=64)), + ("prompt_input", models.CharField(max_length=1024)), + ("promoted", models.BooleanField(default=False)), + ("associated_workflow", models.IntegerField(null=True)), + ( + "created_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="created_prompts", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="modified_prompts", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "project", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="project.project", + ), + ), + ], + ), + migrations.AddConstraint( + model_name="prompt", + constraint=models.UniqueConstraint( + fields=("project", "version_name"), + name="unique_project_version", + ), + ), + ] diff --git a/backend/prompt/migrations/__init__.py b/backend/prompt/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/prompt/models.py b/backend/prompt/models.py new file mode 100644 index 000000000..65af29c35 --- /dev/null +++ b/backend/prompt/models.py @@ -0,0 +1,53 @@ +import uuid + +from account.models import User +from django.db import models +from project.models import Project +from utils.models.base_model import BaseModel + +VERSION_NAME_SIZE = 64 +PROMPT_INPUT_SIZE = 1024 + + +class Prompt(BaseModel): + """Stores data related to a prompt created by a :model:`account.User` in an + :model:`account.Org` for a :model:`project.Project`. + + Every org, project, version_name is assumed to be unique + """ + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + project = models.ForeignKey(Project, on_delete=models.CASCADE) + version_name = models.CharField(max_length=VERSION_NAME_SIZE) + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="created_prompts", + null=True, + blank=True, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="modified_prompts", + null=True, + blank=True, + ) + prompt_input = models.CharField(max_length=PROMPT_INPUT_SIZE) + promoted = models.BooleanField(default=False) + # TODO: Replace once Workflow model is added + # associated_workflow = models.ForeignKey( + # "Workflow", on_delete=models.CASCADE) + associated_workflow = models.IntegerField(null=True) + + def __str__(self) -> str: + return f"Prompt({self.id}, input: {self.prompt_input}, \ + version: {self.version_name}, project: {self.project})" + + class Meta: + constraints = [ + models.UniqueConstraint( + fields=["project", "version_name"], + name="unique_project_version", + ), + ] diff --git a/backend/prompt/serializers.py b/backend/prompt/serializers.py new file mode 100644 index 000000000..add5662b7 --- /dev/null +++ b/backend/prompt/serializers.py @@ -0,0 +1,19 @@ +from typing import Any + +from rest_framework import serializers + +from .models import Prompt + + +class PromptSerializer(serializers.ModelSerializer): + def create(self, validated_data: dict[str, Any]) -> Any: + validated_data["created_by"] = self.context.get("request")._user + return super().create(validated_data) + + def update(self, instance: Any, validated_data: dict[str, Any]) -> Any: + validated_data["modified_by"] = self.context.get("request")._user + return super().update(instance, validated_data) + + class Meta: + model = Prompt + fields = "__all__" diff --git a/backend/prompt/tests/conftest.py b/backend/prompt/tests/conftest.py new file mode 100644 index 000000000..0d9415cc0 --- /dev/null +++ b/backend/prompt/tests/conftest.py @@ -0,0 +1,10 @@ +import pytest + +from django.core.management import call_command + +@pytest.fixture(scope='session') +def django_db_setup(django_db_blocker): + + fixtures = ["./prompt/tests/fixtures/prompts_001.json"] + with django_db_blocker.unblock(): + call_command('loaddata', *fixtures) \ No newline at end of file diff --git a/backend/prompt/tests/fixtures/prompts_001.json b/backend/prompt/tests/fixtures/prompts_001.json new file mode 100644 index 000000000..792e35066 --- /dev/null +++ b/backend/prompt/tests/fixtures/prompts_001.json @@ -0,0 +1,81 @@ +[ +{ + "model": "account.org", + "pk": 1, + "fields": { + "org_name": "Zipstack", + "created_by": 1, + "modified_by": 1, + "modified_at": "2023-06-14T05:28:47.739Z" + } +}, +{ + "model": "account.user", + "pk": 1, + "fields": { + "org": 1, + "email": "johndoe@gmail.com", + "first_name": "John", + "last_name": "Doe", + "is_admin": true, + "created_by": null, + "modified_by": null, + "modified_at": "2023-06-14T05:28:47.744Z" + } +}, +{ + "model": "account.user", + "pk": 2, + "fields": { + "org": 1, + "email": "user1@gmail.com", + "first_name": "Ron", + "last_name": "Stone", + "is_admin": false, + "created_by": 1, + "modified_by": 1, + "modified_at": "2023-06-14T05:28:47.750Z" + } +}, +{ + "model": "project.project", + "pk": 1, + "fields": { + "org": 1, + "project_name": "Unstract Test", + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.759Z" + } +}, +{ + "model": "prompt.prompt", + "pk": 1, + "fields": { + "org": 1, + "project": 1, + "version_name": "v0.1.0", + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.761Z", + "prompt_input": "You are a Django programmer, write a REST API to support CRUD on a simple model", + "promoted": false, + "associated_workflow": null + } +}, +{ + "model": "prompt.prompt", + "pk": 2, + "fields": { + "org": 1, + "project": 1, + "version_name": "v0.1.1", + "created_by": 2, + "modified_by": 2, + "modified_at": "2023-06-14T05:28:47.764Z", + "prompt_input": "You are a poet (William Wordsworth), write a poem on generative AI", + "promoted": false, + "associated_workflow": null + } +} +] diff --git a/backend/prompt/tests/test_urls.py b/backend/prompt/tests/test_urls.py new file mode 100644 index 000000000..f4f2799fe --- /dev/null +++ b/backend/prompt/tests/test_urls.py @@ -0,0 +1,122 @@ +import pytest +from django.urls import reverse +from rest_framework import status +from rest_framework.test import APITestCase + +from prompt.models import Prompt + +pytestmark = pytest.mark.django_db + + +@pytest.mark.prompt +class TestPrompts(APITestCase): + + def test_prompts_list(self): + """Ensure we can list all prompts.""" + url = reverse("prompts_v1-list") + response = self.client.get(url) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(len(response.data), 2) + + def test_prompts_detail(self): + """Ensure we can retrieve a single prompt.""" + url = reverse("prompts_v1-detail", kwargs={"pk": 2}) + response = self.client.get(url) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data["version_name"], "v0.1.1") + + def test_prompts_detail_throw_404(self): + """Tests whether a 404 error is thrown on retrieving a prompt.""" + url = reverse("prompts-detail", + kwargs={"pk": 200}) # Prompt doesn't exist + response = self.client.get(url) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_prompts_create(self): + """Ensure we can create a new prompt.""" + url = reverse("prompts_v1-list") + data = { + "org": 1, + "project": 1, + "version_name": "v0.1.2", + "created_by": 2, + "modified_by": 2, + "prompt_input": "You're a CS undergrad looking to receive an admit from a \ + university for a masters in AI, write a convincing SOP", + "promoted": False, + } + response = self.client.post(url, data, format="json") + pk = response.data["id"] + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(Prompt.objects.count(), 3) + self.assertEqual(Prompt.objects.get(pk=pk).version_name, "v0.1.2") + + def test_prompts_create_throw_bad_request(self): + """Ensure we throw an error in case of a bad request.""" + url = reverse("prompts_v1-list") + data = { + "org": 200, # This org does not exist + "project": 1, + "version_name": "v0.1.2", + "created_by": 2, + "modified_by": 2, + "prompt_input": "You're a CS undergrad looking to receive an admit from a \ + university for a masters in AI, write a convincing SOP", + "promoted": False, + } + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_prompts_update(self): + """Tests the PUT method.""" + url = reverse("prompts_v1-detail", kwargs={"pk": 2}) + data = { + "org": 1, + "project": 1, + "version_name": "v0.1.3", + "created_by": 2, + "modified_by": 2, + "prompt_input": "You're a CS undergrad looking to receive an admit from a \ + university for a masters in AI, write a convincing SOP", + "promoted": False, + } + response = self.client.put(url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_200_OK) + pk = response.data["id"] + self.assertEqual(Prompt.objects.get(pk=pk).version_name, "v0.1.3") + + def test_prompts_update_bad_request(self): + """Tests the PUT method for 400 error.""" + url = reverse("prompts_v1-detail", kwargs={"pk": 2}) + data = { + "org": 200, # This org does not exist + "project": 1, + "version_name": "v0.1.3", + "created_by": 2, + "modified_by": 2, + "prompt_input": "You're a CS undergrad looking to receive an admit from a \ + university for a masters in AI, write a convincing SOP", + "promoted": False, + } + response = self.client.put(url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_prompts_partial_update(self): + """Tests the PATCH method.""" + url = reverse("prompts_v1-detail", kwargs={"pk": 2}) + data = {"promoted": True} + response = self.client.patch(url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_200_OK) + pk = response.data["id"] + self.assertEqual(Prompt.objects.get(pk=pk).promoted, True) + + def test_prompts_delete(self): + """Tests the DELETE method.""" + url = reverse("prompts_v1-detail", kwargs={"pk": 2}) + response = self.client.delete(url, format="json") + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + + # Check if data was deleted as well + url = reverse("prompts_v1-detail", kwargs={"pk": 2}) + response = self.client.get(url) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) diff --git a/backend/prompt/urls.py b/backend/prompt/urls.py new file mode 100644 index 000000000..809ac5c4a --- /dev/null +++ b/backend/prompt/urls.py @@ -0,0 +1,20 @@ +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns +from .views import PromptViewSet + +prompt_list = PromptViewSet.as_view({ + 'get': 'list', + 'post': 'create' +}) +prompt_detail = PromptViewSet.as_view({ + 'get': 'retrieve', + 'put': 'update', + 'patch': 'partial_update', + 'delete': 'destroy' +}) + +urlpatterns = format_suffix_patterns([ + path('prompt/', prompt_list, name='prompt-list'), + path('prompt//', prompt_detail, name='prompt-detail'), +]) + diff --git a/backend/prompt/views.py b/backend/prompt/views.py new file mode 100644 index 000000000..9949ae5de --- /dev/null +++ b/backend/prompt/views.py @@ -0,0 +1,46 @@ +from typing import Any + +from account.custom_exceptions import DuplicateData +from django.db import IntegrityError +from prompt.constants import PromptErrors +from rest_framework import status, viewsets +from rest_framework.decorators import action +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning + +from .models import Prompt +from .serializers import PromptSerializer + + +class PromptViewSet(viewsets.ModelViewSet): + """Used to view and edit prompts. + + Handles GET,POST,PUT,PATCH and DELETE + """ + + versioning_class = URLPathVersioning + queryset = Prompt.objects.all() + serializer_class = PromptSerializer + + @action(detail=False) + def get_all_prompt(self, request: Request) -> Response: + # has not specific funstions. Added for testing purpose + serializer = self.get_serializer(many=True) + return Response(serializer.data) + + def create(self, request: Any) -> Response: + # Overriding default exception behaviour + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + try: + self.perform_create(serializer) + except IntegrityError: + raise DuplicateData( + f"{PromptErrors.PROMPT_EXISTS}, {PromptErrors.DUPLICATE_API}" + ) + + headers = self.get_success_headers(serializer.data) + return Response( + serializer.data, status=status.HTTP_201_CREATED, headers=headers + ) diff --git a/backend/prompt_studio/__init__.py b/backend/prompt_studio/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/prompt_studio/prompt_profile_manager/__init__.py b/backend/prompt_studio/prompt_profile_manager/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/prompt_studio/prompt_profile_manager/admin.py b/backend/prompt_studio/prompt_profile_manager/admin.py new file mode 100644 index 000000000..6878f3f43 --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import ProfileManager + +admin.site.register(ProfileManager) diff --git a/backend/prompt_studio/prompt_profile_manager/apps.py b/backend/prompt_studio/prompt_profile_manager/apps.py new file mode 100644 index 000000000..635132b93 --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ProfileManager(AppConfig): + name = "prompt_studio.prompt_profile_manager" diff --git a/backend/prompt_studio/prompt_profile_manager/constants.py b/backend/prompt_studio/prompt_profile_manager/constants.py new file mode 100644 index 000000000..f474100bb --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/constants.py @@ -0,0 +1,16 @@ +class ProfileManagerKeys: + CREATED_BY = "created_by" + TOOL_ID = "tool_id" + PROMPTS = "prompts" + ADAPTER_NAME = "adapter_name" + LLM = "llm" + VECTOR_STORE = "vector_store" + EMBEDDING_MODEL = "embedding_model" + X2TEXT = "x2text" + + +class ProfileManagerErrors: + SERIALIZATION_FAILED = "Data Serialization Failed." + PROFILE_NAME_EXISTS = "Profile with the name already exists" + DUPLICATE_API = "It appears that a duplicate call may have been made." + PLATFORM_ERROR = "Seems an error occured in Platform Service." diff --git a/backend/prompt_studio/prompt_profile_manager/exceptions.py b/backend/prompt_studio/prompt_profile_manager/exceptions.py new file mode 100644 index 000000000..023f6ad1c --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/exceptions.py @@ -0,0 +1,6 @@ +from rest_framework.exceptions import APIException + + +class PlatformServiceError(APIException): + status_code = 400 + default_detail = "Seems an error occured in Platform Service." diff --git a/backend/prompt_studio/prompt_profile_manager/migrations/0001_initial.py b/backend/prompt_studio/prompt_profile_manager/migrations/0001_initial.py new file mode 100644 index 000000000..72e40bcc6 --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/migrations/0001_initial.py @@ -0,0 +1,109 @@ +# Generated by Django 4.2.1 on 2024-01-20 08:04 + +import uuid + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="ProfileManager", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "profile_id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ("profile_name", models.TextField(unique=True)), + ( + "vector_store", + models.TextField( + db_comment="Field to store the chosen vector store." + ), + ), + ("embedding_model", models.TextField()), + ( + "llm", + models.TextField( + db_comment="Field to store the LLM chosen by the user" + ), + ), + ("chunk_size", models.IntegerField(blank=True, null=True)), + ("chunk_overlap", models.IntegerField(blank=True, null=True)), + ("reindex", models.BooleanField(default=False)), + ("vector_size", models.IntegerField()), + ( + "pdf_to_text_converters", + models.TextField(blank=True, null=True), + ), + ( + "retrival_strategy", + models.TextField( + blank=True, + choices=[ + ("simple", "Simple retrieval"), + ("subquestion", "Subquestion from prompt"), + ("vector+keyword", "Uses vector for retrieval"), + ], + db_comment="Field to store the retrieval strategy for prompts", + ), + ), + ( + "similarity_top_k", + models.IntegerField( + blank=True, + db_comment="Field to store matching count", + null=True, + ), + ), + ( + "section", + models.TextField( + blank=True, + db_comment="Field to store limit to section", + null=True, + ), + ), + ( + "created_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="profile_created_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="profile_modified_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/backend/prompt_studio/prompt_profile_manager/migrations/0002_remove_profilemanager_vector_size_and_more.py b/backend/prompt_studio/prompt_profile_manager/migrations/0002_remove_profilemanager_vector_size_and_more.py new file mode 100644 index 000000000..2fbed11eb --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/migrations/0002_remove_profilemanager_vector_size_and_more.py @@ -0,0 +1,47 @@ +# Generated by Django 4.2.1 on 2024-01-24 14:29 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("adapter_processor", "0002_adapterinstance_unique_adapter"), + ("prompt_profile_manager", "0001_initial"), + ] + + operations = [ + migrations.RemoveField( + model_name="profilemanager", + name="vector_size", + ), + migrations.AlterField( + model_name="profilemanager", + name="embedding_model", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="profile_manager_embedding", + to="adapter_processor.adapterinstance", + ), + ), + migrations.AlterField( + model_name="profilemanager", + name="llm", + field=models.ForeignKey( + db_comment="Field to store the LLM chosen by the user", + on_delete=django.db.models.deletion.PROTECT, + related_name="profile_manager_llm", + to="adapter_processor.adapterinstance", + ), + ), + migrations.AlterField( + model_name="profilemanager", + name="vector_store", + field=models.ForeignKey( + db_comment="Field to store the chosen vector store.", + on_delete=django.db.models.deletion.PROTECT, + related_name="profile_manager_vector", + to="adapter_processor.adapterinstance", + ), + ), + ] diff --git a/backend/prompt_studio/prompt_profile_manager/migrations/0002_rename_updated_at_profilemanager_modified_at.py b/backend/prompt_studio/prompt_profile_manager/migrations/0002_rename_updated_at_profilemanager_modified_at.py new file mode 100644 index 000000000..6ffd7fc96 --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/migrations/0002_rename_updated_at_profilemanager_modified_at.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.1 on 2024-01-23 19:02 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("prompt_profile_manager", "0001_initial"), + ] + + operations = [ + migrations.RenameField( + model_name="profilemanager", + old_name="updated_at", + new_name="modified_at", + ), + ] diff --git a/backend/prompt_studio/prompt_profile_manager/migrations/0003_merge_20240125_0530.py b/backend/prompt_studio/prompt_profile_manager/migrations/0003_merge_20240125_0530.py new file mode 100644 index 000000000..ed6213d52 --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/migrations/0003_merge_20240125_0530.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.1 on 2024-01-25 05:30 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ( + "prompt_profile_manager", + "0002_remove_profilemanager_vector_size_and_more", + ), + ( + "prompt_profile_manager", + "0002_rename_updated_at_profilemanager_modified_at", + ), + ] + + operations = [] diff --git a/backend/prompt_studio/prompt_profile_manager/migrations/0004_rename_retrival_strategy_profilemanager_retrieval_strategy.py b/backend/prompt_studio/prompt_profile_manager/migrations/0004_rename_retrival_strategy_profilemanager_retrieval_strategy.py new file mode 100644 index 000000000..19ae21115 --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/migrations/0004_rename_retrival_strategy_profilemanager_retrieval_strategy.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.1 on 2024-02-08 09:47 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("prompt_profile_manager", "0003_merge_20240125_0530"), + ] + + operations = [ + migrations.RenameField( + model_name="profilemanager", + old_name="retrival_strategy", + new_name="retrieval_strategy", + ), + ] diff --git a/backend/prompt_studio/prompt_profile_manager/migrations/0005_removed_converter_and_added_x2text_foreign_key.py b/backend/prompt_studio/prompt_profile_manager/migrations/0005_removed_converter_and_added_x2text_foreign_key.py new file mode 100644 index 000000000..45def44f7 --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/migrations/0005_removed_converter_and_added_x2text_foreign_key.py @@ -0,0 +1,65 @@ +# Generated by Django 4.2.1 on 2024-02-23 11:10 + +import json + +import django.db.models.deletion +from cryptography.fernet import Fernet +from django.db import migrations, models + + +def fill_with_default_x2text(apps, schema): + ProfileManager = apps.get_model("prompt_profile_manager", "ProfileManager") + AdapterInstance = apps.get_model("adapter_processor", "AdapterInstance") + EncryptionSecret = apps.get_model("account", "EncryptionSecret") + encryption_secret = EncryptionSecret.objects.get() + f: Fernet = Fernet(encryption_secret.key.encode("utf-8")) + metadata = { + "url": "http://unstract-unstructured-io:8000/general/v0/general" + } + json_string = json.dumps(metadata) + metadata_b = f.encrypt(json_string.encode("utf-8")) + + adapter_instance = AdapterInstance( + adapter_name="DefaultX2text", + adapter_id="unstructuredcommunity|eeed506f-1875-457f-9101-846fc7115676", + adapter_type="X2TEXT", + adapter_metadata_b=metadata_b, + ) + adapter_instance.save() + ProfileManager.objects.filter(x2text__isnull=True).update( + x2text=adapter_instance + ) + + +def reversal_x2text(*args): + """Reversal is NOOP since x2text is simply dropped during reverse.""" + + +class Migration(migrations.Migration): + dependencies = [ + ("account", "0005_encryptionsecret"), + ("adapter_processor", "0004_alter_adapterinstance_adapter_type"), + ( + "prompt_profile_manager", + "0004_rename_retrival_strategy_profilemanager_retrieval_strategy", + ), + ] + + operations = [ + migrations.RemoveField( + model_name="profilemanager", + name="pdf_to_text_converters", + ), + migrations.AddField( + model_name="profilemanager", + name="x2text", + field=models.ForeignKey( + db_comment="Field to store the X2Text Adapter chosen by the user", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="profile_manager_x2text", + to="adapter_processor.adapterinstance", + ), + ), + migrations.RunPython(fill_with_default_x2text, reversal_x2text), + ] diff --git a/backend/prompt_studio/prompt_profile_manager/migrations/0006_alter_profilemanager_x2text.py b/backend/prompt_studio/prompt_profile_manager/migrations/0006_alter_profilemanager_x2text.py new file mode 100644 index 000000000..e34d26796 --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/migrations/0006_alter_profilemanager_x2text.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.1 on 2024-02-23 17:02 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("adapter_processor", "0004_alter_adapterinstance_adapter_type"), + ( + "prompt_profile_manager", + "0005_removed_converter_and_added_x2text_foreign_key", + ), + ] + + operations = [ + migrations.AlterField( + model_name="profilemanager", + name="x2text", + field=models.ForeignKey( + db_comment="Field to store the X2Text Adapter chosen by the user", + on_delete=django.db.models.deletion.PROTECT, + related_name="profile_manager_x2text", + to="adapter_processor.adapterinstance", + ), + ), + ] diff --git a/backend/prompt_studio/prompt_profile_manager/migrations/__init__.py b/backend/prompt_studio/prompt_profile_manager/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/prompt_studio/prompt_profile_manager/models.py b/backend/prompt_studio/prompt_profile_manager/models.py new file mode 100644 index 000000000..99f65433b --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/models.py @@ -0,0 +1,81 @@ +import uuid + +from account.models import User +from adapter_processor.models import AdapterInstance +from django.db import models +from utils.models.base_model import BaseModel + + +class ProfileManager(BaseModel): + """Model to store the LLM Triad management details for Prompt.""" + + class RetrievalStrategy(models.TextChoices): + SIMPLE = "simple", "Simple retrieval" + SUBQUESTION = "subquestion", "Subquestion from prompt" + VECTOR = "vector+keyword", "Uses vector for retrieval" + + profile_id = models.UUIDField( + primary_key=True, default=uuid.uuid4, editable=False + ) + profile_name = models.TextField(unique=True, blank=False) + vector_store = models.ForeignKey( + AdapterInstance, + db_comment="Field to store the chosen vector store.", + blank=False, + null=False, + on_delete=models.PROTECT, + related_name="profile_manager_vector", + ) + embedding_model = models.ForeignKey( + AdapterInstance, + blank=False, + null=False, + on_delete=models.PROTECT, + related_name="profile_manager_embedding", + ) + llm = models.ForeignKey( + AdapterInstance, + db_comment="Field to store the LLM chosen by the user", + blank=False, + null=False, + on_delete=models.PROTECT, + related_name="profile_manager_llm", + ) + x2text = models.ForeignKey( + AdapterInstance, + db_comment="Field to store the X2Text Adapter chosen by the user", + blank=False, + null=False, + on_delete=models.PROTECT, + related_name="profile_manager_x2text", + ) + chunk_size = models.IntegerField(null=True, blank=True) + chunk_overlap = models.IntegerField(null=True, blank=True) + reindex = models.BooleanField(default=False) + retrieval_strategy = models.TextField( + choices=RetrievalStrategy.choices, + blank=True, + db_comment="Field to store the retrieval strategy for prompts", + ) + similarity_top_k = models.IntegerField( + blank=True, null=True, db_comment="Field to store matching count" + ) + section = models.TextField( + blank=True, null=True, db_comment="Field to store limit to section" + ) + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="profile_created_by", + null=True, + blank=True, + editable=False, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="profile_modified_by", + null=True, + blank=True, + editable=False, + ) diff --git a/backend/prompt_studio/prompt_profile_manager/serializers.py b/backend/prompt_studio/prompt_profile_manager/serializers.py new file mode 100644 index 000000000..a217a4360 --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/serializers.py @@ -0,0 +1,40 @@ +import logging + +from adapter_processor.adapter_processor import AdapterProcessor +from prompt_studio.prompt_profile_manager.constants import ProfileManagerKeys + +from backend.serializers import AuditSerializer + +from .models import ProfileManager + +logger = logging.getLogger(__name__) + + +class ProfileManagerSerializer(AuditSerializer): + class Meta: + model = ProfileManager + fields = "__all__" + + def to_representation(self, instance): # type: ignore + rep: dict[str, str] = super().to_representation(instance) + llm = rep[ProfileManagerKeys.LLM] + embedding = rep[ProfileManagerKeys.EMBEDDING_MODEL] + vector_db = rep[ProfileManagerKeys.VECTOR_STORE] + x2text = rep[ProfileManagerKeys.X2TEXT] + if llm: + rep[ + ProfileManagerKeys.LLM + ] = AdapterProcessor.get_adapter_instance_by_id(llm) + if embedding: + rep[ + ProfileManagerKeys.EMBEDDING_MODEL + ] = AdapterProcessor.get_adapter_instance_by_id(embedding) + if vector_db: + rep[ + ProfileManagerKeys.VECTOR_STORE + ] = AdapterProcessor.get_adapter_instance_by_id(vector_db) + if x2text: + rep[ + ProfileManagerKeys.X2TEXT + ] = AdapterProcessor.get_adapter_instance_by_id(x2text) + return rep diff --git a/backend/prompt_studio/prompt_profile_manager/urls.py b/backend/prompt_studio/prompt_profile_manager/urls.py new file mode 100644 index 000000000..7de978a83 --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/urls.py @@ -0,0 +1,32 @@ +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns + +from .views import ProfileManagerView + +profile_manager_list = ProfileManagerView.as_view( + {"get": "list", "post": "create"} +) +profile_manager_detail = ProfileManagerView.as_view( + { + "get": "retrieve", + "put": "update", + "patch": "partial_update", + "delete": "destroy", + } +) + + +urlpatterns = format_suffix_patterns( + [ + path( + "profile-manager/", + profile_manager_list, + name="profile-manager-list", + ), + path( + "profile-manager//", + profile_manager_detail, + name="profile-manager-detail", + ), + ] +) diff --git a/backend/prompt_studio/prompt_profile_manager/views.py b/backend/prompt_studio/prompt_profile_manager/views.py new file mode 100644 index 000000000..aae07fbb3 --- /dev/null +++ b/backend/prompt_studio/prompt_profile_manager/views.py @@ -0,0 +1,59 @@ +from typing import Any, Optional + +from account.custom_exceptions import DuplicateData +from django.db import IntegrityError +from django.db.models import QuerySet +from django.http import HttpRequest +from permissions.permission import IsOwner +from prompt_studio.prompt_profile_manager.constants import ( + ProfileManagerErrors, + ProfileManagerKeys, +) +from prompt_studio.prompt_profile_manager.serializers import ( + ProfileManagerSerializer, +) +from rest_framework import status, viewsets +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning +from utils.filtering import FilterHelper + +from .models import ProfileManager + + +class ProfileManagerView(viewsets.ModelViewSet): + """Viewset to handle all Custom tool related operations.""" + + versioning_class = URLPathVersioning + permission_classes = [IsOwner] + serializer_class = ProfileManagerSerializer + + def get_queryset(self) -> Optional[QuerySet]: + filter_args = FilterHelper.build_filter_args( + self.request, + ProfileManagerKeys.CREATED_BY, + ) + if filter_args: + queryset = ProfileManager.objects.filter( + created_by=self.request.user, **filter_args + ) + else: + queryset = ProfileManager.objects.filter( + created_by=self.request.user + ) + return queryset + + def create( + self, request: HttpRequest, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> Response: + serializer = self.get_serializer(data=request.data) + # Overriding default exception behaviour + # TO DO : Handle model related exceptions. + serializer.is_valid(raise_exception=True) + try: + self.perform_create(serializer) + except IntegrityError: + raise DuplicateData( + f"{ProfileManagerErrors.PROFILE_NAME_EXISTS}, \ + {ProfileManagerErrors.DUPLICATE_API}" + ) + return Response(serializer.data, status=status.HTTP_201_CREATED) diff --git a/backend/prompt_studio/prompt_studio/__init__.py b/backend/prompt_studio/prompt_studio/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/prompt_studio/prompt_studio/admin.py b/backend/prompt_studio/prompt_studio/admin.py new file mode 100644 index 000000000..bbcd76c6e --- /dev/null +++ b/backend/prompt_studio/prompt_studio/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import ToolStudioPrompt + +admin.site.register(ToolStudioPrompt) diff --git a/backend/prompt_studio/prompt_studio/apps.py b/backend/prompt_studio/prompt_studio/apps.py new file mode 100644 index 000000000..9e30ea8b3 --- /dev/null +++ b/backend/prompt_studio/prompt_studio/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ToolStudioPrompt(AppConfig): + name = "prompt_studio.prompt_studio" diff --git a/backend/prompt_studio/prompt_studio/constants.py b/backend/prompt_studio/prompt_studio/constants.py new file mode 100644 index 000000000..4df053d82 --- /dev/null +++ b/backend/prompt_studio/prompt_studio/constants.py @@ -0,0 +1,28 @@ +class ToolStudioPromptKeys: + CREATED_BY = "created_by" + TOOL_ID = "tool_id" + NUMBER = "Number" + FLOAT = "Float" + PG_VECTOR = "Postgres pg_vector" + ANSWERS = "answers" + UNIQUE_FILE_ID = "unique_file_id" + ID = "id" + FILE_NAME = "file_name" + UNDEFINED = "undefined" + ACTIVE = "active" + PROMPT_KEY = "prompt_key" + EVAL_METRIC_PREFIX = "eval_" + EVAL_RESULT_DELIM = "__" + + +class ToolStudioPromptErrors: + SERIALIZATION_FAILED = "Data Serialization Failed." + DUPLICATE_API = "It appears that a duplicate call may have been made." + PROMPT_NAME_EXISTS = "Prompt with the name already exists" + + +class LogLevels: + INFO = "INFO" + ERROR = "ERROR" + DEBUG = "DEBUG" + RUN = "RUN" diff --git a/backend/prompt_studio/prompt_studio/exceptions.py b/backend/prompt_studio/prompt_studio/exceptions.py new file mode 100644 index 000000000..885ee092f --- /dev/null +++ b/backend/prompt_studio/prompt_studio/exceptions.py @@ -0,0 +1,27 @@ +from rest_framework.exceptions import APIException + + +class IndexingError(APIException): + status_code = 400 + default_detail = "Error while indexing file" + + +class FilenameMissingError(APIException): + status_code = 400 + default_detail = "No file selected to parse." + + +class AnswerFetchError(APIException): + status_code = 400 + default_detail = "Error occured while fetching response for the prompt" + + +class ToolNotValid(APIException): + status_code = 400 + default_detail = "Custom tool is not valid." + + +class PromptNotValid(APIException): + status_code = 400 + default_detail = "Input prompt instance is not valid.\ + Seems it is either empty or no prompt is mapped." diff --git a/backend/prompt_studio/prompt_studio/migrations/0001_initial.py b/backend/prompt_studio/prompt_studio/migrations/0001_initial.py new file mode 100644 index 000000000..0fb94aab1 --- /dev/null +++ b/backend/prompt_studio/prompt_studio/migrations/0001_initial.py @@ -0,0 +1,145 @@ +# Generated by Django 4.2.1 on 2024-01-20 08:04 + +import uuid + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("prompt_studio_core", "0001_initial"), + ("prompt_profile_manager", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="ToolStudioPrompt", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "prompt_id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "prompt_key", + models.TextField( + db_comment="Field to store the prompt key", unique=True + ), + ), + ( + "enforce_type", + models.TextField( + blank=True, + choices=[ + ("Text", "Response sent as Text"), + ("number", "Response sent as number"), + ("email", "Response sent as email"), + ("date", "Response sent as date"), + ("boolean", "Response sent as boolean"), + ("json", "Response sent as json"), + ], + db_comment="Field to store the type in which the response to be returned.", + ), + ), + ( + "prompt", + models.TextField(db_comment="Field to store the prompt"), + ), + ("sequence_number", models.IntegerField(blank=True, null=True)), + ( + "prompt_type", + models.TextField( + blank=True, + choices=[ + ("PROMPT", "Response sent as Text"), + ("NOTES", "Response sent as float"), + ], + db_comment="Field to store the type of the input prompt", + ), + ), + ("output", models.TextField(blank=True)), + ( + "assert_prompt", + models.TextField( + blank=True, + db_comment="Field to store the asserted prompt", + null=True, + ), + ), + ( + "assertion_failure_prompt", + models.TextField( + blank=True, + db_comment="Field to store the prompt key", + null=True, + ), + ), + ("is_assert", models.BooleanField(default=False)), + ("active", models.BooleanField(default=True)), + ( + "output_metadata", + models.JSONField( + db_column="output_metadata", + db_comment="JSON adapter metadata for the FE to load the pagination", + default=dict, + ), + ), + ( + "created_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="prompt_created_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="prompt_modified_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "profile_manager", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="prompt_profile_manager", + to="prompt_profile_manager.profilemanager", + ), + ), + ( + "tool_id", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="mapped_prompt", + to="prompt_studio_core.customtool", + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/backend/prompt_studio/prompt_studio/migrations/0002_prompt_eval_metrics.py b/backend/prompt_studio/prompt_studio/migrations/0002_prompt_eval_metrics.py new file mode 100644 index 000000000..22f61a29f --- /dev/null +++ b/backend/prompt_studio/prompt_studio/migrations/0002_prompt_eval_metrics.py @@ -0,0 +1,48 @@ +# Generated by Django 4.2.1 on 2024-01-22 18:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('prompt_studio', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='toolstudioprompt', + name='eval_guidance_completeness', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='toolstudioprompt', + name='eval_guidance_toxicity', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='toolstudioprompt', + name='eval_quality_correctness', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='toolstudioprompt', + name='eval_quality_faithfulness', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='toolstudioprompt', + name='eval_quality_relevance', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='toolstudioprompt', + name='eval_security_pii', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='toolstudioprompt', + name='evaluate', + field=models.BooleanField(default=True), + ), + ] diff --git a/backend/prompt_studio/prompt_studio/migrations/0003_remove_toolstudioprompt_updated_at_and_more.py b/backend/prompt_studio/prompt_studio/migrations/0003_remove_toolstudioprompt_updated_at_and_more.py new file mode 100644 index 000000000..74a6713c6 --- /dev/null +++ b/backend/prompt_studio/prompt_studio/migrations/0003_remove_toolstudioprompt_updated_at_and_more.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.1 on 2024-01-23 19:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("prompt_studio", "0002_prompt_eval_metrics"), + ] + + operations = [ + migrations.RemoveField( + model_name="toolstudioprompt", + name="updated_at", + ), + migrations.AddField( + model_name="toolstudioprompt", + name="modified_at", + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/backend/prompt_studio/prompt_studio/migrations/0004_alter_toolstudioprompt_prompt.py b/backend/prompt_studio/prompt_studio/migrations/0004_alter_toolstudioprompt_prompt.py new file mode 100644 index 000000000..72be66dd4 --- /dev/null +++ b/backend/prompt_studio/prompt_studio/migrations/0004_alter_toolstudioprompt_prompt.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.1 on 2024-02-13 11:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("prompt_studio", "0003_remove_toolstudioprompt_updated_at_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="toolstudioprompt", + name="prompt", + field=models.TextField( + blank=True, db_comment="Field to store the prompt" + ), + ), + ] diff --git a/backend/prompt_studio/prompt_studio/migrations/__init__.py b/backend/prompt_studio/prompt_studio/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/prompt_studio/prompt_studio/models.py b/backend/prompt_studio/prompt_studio/models.py new file mode 100644 index 000000000..2e783b692 --- /dev/null +++ b/backend/prompt_studio/prompt_studio/models.py @@ -0,0 +1,117 @@ +import uuid + +from account.models import User +from django.db import models +from prompt_studio.prompt_profile_manager.models import ProfileManager +from prompt_studio.prompt_studio_core.models import CustomTool +from utils.models.base_model import BaseModel + + +class ToolStudioPrompt(BaseModel): + """Model class while store Prompt data for Custom Tool Studio. + + It has Many to one relation with CustomTool for ToolStudio. + """ + + class EnforceType(models.TextChoices): + TEXT = "Text", "Response sent as Text" + NUMBER = "number", "Response sent as number" + EMAIL = "email", "Response sent as email" + DATE = "date", "Response sent as date" + BOOLEAN = "boolean", "Response sent as boolean" + JSON = "json", "Response sent as json" + + class PromptType(models.TextChoices): + PROMPT = "PROMPT", "Response sent as Text" + NOTES = "NOTES", "Response sent as float" + + class Mode(models.TextChoices): + DEFAULT = "Default", "Default choice for output" + + prompt_id = models.UUIDField( + primary_key=True, default=uuid.uuid4, editable=False + ) + prompt_key = models.TextField( + blank=False, + db_comment="Field to store the prompt key", + unique=True, + ) + enforce_type = models.TextField( + blank=True, + db_comment="Field to store the type in \ + which the response to be returned.", + choices=EnforceType.choices, + ) + prompt = models.TextField( + blank=True, db_comment="Field to store the prompt", unique=False + ) + tool_id = models.ForeignKey( + CustomTool, + on_delete=models.SET_NULL, + related_name="mapped_prompt", + null=True, + blank=True, + ) + sequence_number = models.IntegerField(null=True, blank=True) + prompt_type = models.TextField( + blank=True, + db_comment="Field to store the type of the input prompt", + choices=PromptType.choices, + ) + profile_manager = models.ForeignKey( + ProfileManager, + on_delete=models.SET_NULL, + related_name="prompt_profile_manager", + null=True, + blank=True, + ) + output = models.TextField(blank=True) + assert_prompt = models.TextField( + blank=True, + null=True, + db_comment="Field to store the asserted prompt", + unique=False, + ) + assertion_failure_prompt = models.TextField( + blank=True, + null=True, + db_comment="Field to store the prompt key", + unique=False, + ) + is_assert = models.BooleanField(default=False) + active = models.BooleanField(default=True, null=False, blank=False) + output_metadata = models.JSONField( + db_column="output_metadata", + null=False, + blank=False, + default=dict, + db_comment="JSON adapter metadata for the FE to load the pagination", + ) + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="prompt_created_by", + null=True, + blank=True, + editable=False, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="prompt_modified_by", + null=True, + blank=True, + editable=False, + ) + # Eval settings for the prompt + # NOTE: + # - Field name format is eval__ + # - Metric name alone should be UNIQUE across all eval metrics + evaluate = models.BooleanField(default=True) + eval_quality_faithfulness = models.BooleanField(default=True) + eval_quality_correctness = models.BooleanField(default=True) + eval_quality_relevance = models.BooleanField(default=True) + eval_security_pii = models.BooleanField(default=True) + eval_guidance_toxicity = models.BooleanField(default=True) + eval_guidance_completeness = models.BooleanField(default=True) + # diff --git a/backend/prompt_studio/prompt_studio/serializers.py b/backend/prompt_studio/prompt_studio/serializers.py new file mode 100644 index 000000000..18fe6d701 --- /dev/null +++ b/backend/prompt_studio/prompt_studio/serializers.py @@ -0,0 +1,15 @@ +from backend.serializers import AuditSerializer +from rest_framework import serializers + +from .models import ToolStudioPrompt + + +class ToolStudioPromptSerializer(AuditSerializer): + class Meta: + model = ToolStudioPrompt + fields = "__all__" + + +class ToolStudioIndexSerializer(serializers.Serializer): + file_name = serializers.CharField() + tool_id = serializers.CharField() diff --git a/backend/prompt_studio/prompt_studio/urls.py b/backend/prompt_studio/prompt_studio/urls.py new file mode 100644 index 000000000..a0cb10ce4 --- /dev/null +++ b/backend/prompt_studio/prompt_studio/urls.py @@ -0,0 +1,31 @@ +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns + +from .views import ToolStudioPromptView + +prompt_studio_prompt_list = ToolStudioPromptView.as_view( + {"get": "list", "post": "create"} +) +prompt_studio_prompt_detail = ToolStudioPromptView.as_view( + { + "get": "retrieve", + "put": "update", + "patch": "partial_update", + "delete": "destroy", + } +) + +urlpatterns = format_suffix_patterns( + [ + path( + "prompt/", + prompt_studio_prompt_list, + name="prompt-studio-prompt-list", + ), + path( + "prompt//", + prompt_studio_prompt_detail, + name="tool-studio-prompt-detail", + ), + ] +) diff --git a/backend/prompt_studio/prompt_studio/views.py b/backend/prompt_studio/prompt_studio/views.py new file mode 100644 index 000000000..c226d3e36 --- /dev/null +++ b/backend/prompt_studio/prompt_studio/views.py @@ -0,0 +1,67 @@ +import logging +from typing import Any, Optional + +from account.custom_exceptions import DuplicateData +from django.db import IntegrityError +from django.db.models import QuerySet +from django.http import HttpRequest +from prompt_studio.prompt_studio.constants import ( + ToolStudioPromptErrors, + ToolStudioPromptKeys, +) +from rest_framework import status, viewsets +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning +from utils.filtering import FilterHelper + +from .models import ToolStudioPrompt +from .serializers import ToolStudioPromptSerializer + +logger = logging.getLogger(__name__) + + +class ToolStudioPromptView(viewsets.ModelViewSet): + """Viewset to handle all Tool Studio prompt related API logics. + + Args: + viewsets (_type_) + + Raises: + DuplicateData + FilenameMissingError + IndexingError + ValidationError + """ + + versioning_class = URLPathVersioning + serializer_class = ToolStudioPromptSerializer + + def get_queryset(self) -> Optional[QuerySet]: + filter_args = FilterHelper.build_filter_args( + self.request, + ToolStudioPromptKeys.TOOL_ID, + ) + if filter_args: + queryset = ToolStudioPrompt.objects.filter( + created_by=self.request.user, **filter_args + ) + else: + queryset = ToolStudioPrompt.objects.filter( + created_by=self.request.user, + ) + return queryset + + def create( + self, request: HttpRequest, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> Response: + serializer = self.get_serializer(data=request.data) + # TODO : Handle model related exceptions. + serializer.is_valid(raise_exception=True) + try: + self.perform_create(serializer) + except IntegrityError: + raise DuplicateData( + f"{ToolStudioPromptErrors.PROMPT_NAME_EXISTS}, \ + {ToolStudioPromptErrors.DUPLICATE_API}" + ) + return Response(serializer.data, status=status.HTTP_201_CREATED) diff --git a/backend/prompt_studio/prompt_studio_core/__init__.py b/backend/prompt_studio/prompt_studio_core/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/prompt_studio/prompt_studio_core/admin.py b/backend/prompt_studio/prompt_studio_core/admin.py new file mode 100644 index 000000000..e6e1457ea --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import CustomTool + +admin.site.register(CustomTool) diff --git a/backend/prompt_studio/prompt_studio_core/apps.py b/backend/prompt_studio/prompt_studio_core/apps.py new file mode 100644 index 000000000..15184a96e --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class CustomTool(AppConfig): + name = "prompt_studio.prompt_studio_core" diff --git a/backend/prompt_studio/prompt_studio_core/constants.py b/backend/prompt_studio/prompt_studio_core/constants.py new file mode 100644 index 000000000..df5be97e9 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/constants.py @@ -0,0 +1,90 @@ +from enum import Enum + + +class ToolStudioKeys: + CREATED_BY = "created_by" + TOOL_ID = "tool_id" + PROMPTS = "prompts" + PLATFORM_SERVICE_API_KEY = "PLATFORM_SERVICE_API_KEY" + + +class ToolStudioErrors: + SERIALIZATION_FAILED = "Data Serialization Failed." + TOOL_NAME_EXISTS = "Tool with the name already exists" + DUPLICATE_API = "It appears that a duplicate call may have been made." + PLATFORM_ERROR = "Seems an error occured in Platform Service." + PROMPT_NAME_EXISTS = "Prompt with the name already exists" + + +class ToolStudioPromptKeys: + CREATED_BY = "created_by" + TOOL_ID = "tool_id" + NUMBER = "Number" + FLOAT = "Float" + PG_VECTOR = "Postgres pg_vector" + ANSWERS = "answers" + UNIQUE_FILE_ID = "unique_file_id" + ID = "id" + FILE_NAME = "file_name" + FILE_HASH = "file_hash" + UNDEFINED = "undefined" + TOOL_ID = "tool_id" + NAME = "name" + ACTIVE = "active" + PROMPT = "prompt" + CHUNK_SIZE = "chunk-size" + PROMPTX = "promptx" + VECTOR_DB = "vector-db" + EMBEDDING = "embedding" + X2TEXT_ADAPTER = "x2text_adapter" + CHUNK_OVERLAP = "chunk-overlap" + LLM = "llm" + IS_ASSERT = "is_assert" + ASSERTION_FAILURE_PROMPT = "assertion_failure_prompt" + RETRIEVAL_STRATEGY = "retrieval-strategy" + SIMPLE = "simple" + VECTOR_KEYWORD = "vector+keyword" + SUBQUESTION = "subquestion" + TYPE = "type" + NUMBER = "number" + EMAIL = "email" + DATE = "date" + BOOLEAN = "boolean" + JSON = "json" + PREAMBLE = "preamble" + SIMILARITY_TOP_K = "similarity-top-k" + PROMPT_TOKENS = "prompt_tokens" + COMPLETION_TOKENS = "completion_tokens" + TOTAL_TOKENS = "total_tokens" + RESPONSE = "response" + POSTAMBLE = "postamble" + GRAMMAR = "grammar" + WORD = "word" + SYNONYMS = "synonyms" + OUTPUTS = "outputs" + ASSERT_PROMPT = "assert_prompt" + SECTION = "section" + DEFAULT = "default" + REINDEX = "reindex" + EMBEDDING_SUFFIX = "embedding_suffix" + EVAL_METRIC_PREFIX = "eval_" + EVAL_RESULT_DELIM = "__" + EVAL_SETTINGS = "eval_settings" + EVAL_SETTINGS_EVALUATE = "evaluate" + EVAL_SETTINGS_MONITOR_LLM = "monitor_llm" + EVAL_SETTINGS_EXCLUDE_FAILED = "exclude_failed" + + +class LogLevels: + INFO = "INFO" + ERROR = "ERROR" + DEBUG = "DEBUG" + RUN = "RUN" + + +class LogLevel(Enum): + DEBUG = "DEBUG" + INFO = "INFO" + WARN = "WARN" + ERROR = "ERROR" + FATAL = "FATAL" diff --git a/backend/prompt_studio/prompt_studio_core/exceptions.py b/backend/prompt_studio/prompt_studio_core/exceptions.py new file mode 100644 index 000000000..fb417cb1b --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/exceptions.py @@ -0,0 +1,49 @@ +from prompt_studio.prompt_studio_core.constants import ToolStudioErrors +from rest_framework.exceptions import APIException + + +class PlatformServiceError(APIException): + status_code = 400 + default_detail = ToolStudioErrors.PLATFORM_ERROR + + +class ToolNotValid(APIException): + status_code = 400 + default_detail = "Custom tool is not valid." + + +class PromptNotValid(APIException): + status_code = 400 + default_detail = "Input prompt instance is not valid.\ + Seems it is either empty or no prompt is mapped." + + +class IndexingError(APIException): + status_code = 400 + default_detail = "Error while indexing file" + + +class AnswerFetchError(APIException): + status_code = 500 + default_detail = "Error occured while fetching response for the prompt" + + +class DefaultProfileError(APIException): + status_code = 400 + default_detail = "Default profile is not selected. \ + Please select one from Profile manager." + + +class EnvRequired(APIException): + status_code = 404 + default_detail = "Environment variable not set" + + +class OutputSaveError(APIException): + status_code = 500 + default_detail = "Unable to store the output." + + +class ToolDeleteError(APIException): + status_code = 500 + default_detail = "Failed to delete the error" diff --git a/backend/prompt_studio/prompt_studio_core/migrations/0001_initial.py b/backend/prompt_studio/prompt_studio_core/migrations/0001_initial.py new file mode 100644 index 000000000..a22e616ce --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/migrations/0001_initial.py @@ -0,0 +1,124 @@ +# Generated by Django 4.2.1 on 2024-01-20 08:04 + +import uuid + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("prompt_profile_manager", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="CustomTool", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "tool_id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ("tool_name", models.TextField(unique=True)), + ("description", models.TextField()), + ( + "author", + models.TextField( + db_comment="Specific to the user who created the tool." + ), + ), + ( + "icon", + models.TextField( + blank=True, + db_comment="Field to store icon url for the custom tool.", + ), + ), + ( + "output", + models.TextField( + blank=True, + choices=[ + ("JSON", "Output stored as JSON"), + ("YAML", "Output stored as YAML"), + ], + db_comment="Field to store the output format type.", + ), + ), + ( + "log_id", + models.UUIDField( + db_comment="Field to store unique log_id for polling", + default=uuid.uuid4, + ), + ), + ( + "preamble", + models.TextField( + blank=True, db_comment="Preamble to the prompts" + ), + ), + ( + "postamble", + models.TextField( + blank=True, + db_comment="Appended as postable to prompts.", + ), + ), + ( + "prompt_grammer", + models.JSONField( + blank=True, + db_comment="Synonymous words used in prompt", + null=True, + ), + ), + ( + "created_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="tool_created_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "default_profile", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="default_profile", + to="prompt_profile_manager.profilemanager", + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="tool_modified_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/backend/prompt_studio/prompt_studio_core/migrations/0002_alter_customtool_output.py b/backend/prompt_studio/prompt_studio_core/migrations/0002_alter_customtool_output.py new file mode 100644 index 000000000..1d90060e2 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/migrations/0002_alter_customtool_output.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.1 on 2024-01-25 07:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("prompt_studio_core", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="customtool", + name="output", + field=models.TextField( + blank=True, db_comment="Field to store the output format type." + ), + ), + ] diff --git a/backend/prompt_studio/prompt_studio_core/migrations/0002_remove_customtool_updated_at_customtool_modified_at.py b/backend/prompt_studio/prompt_studio_core/migrations/0002_remove_customtool_updated_at_customtool_modified_at.py new file mode 100644 index 000000000..29393e4ca --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/migrations/0002_remove_customtool_updated_at_customtool_modified_at.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.1 on 2024-01-23 19:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("prompt_studio_core", "0001_initial"), + ] + + operations = [ + migrations.RemoveField( + model_name="customtool", + name="updated_at", + ), + migrations.AddField( + model_name="customtool", + name="modified_at", + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/backend/prompt_studio/prompt_studio_core/migrations/0003_merge_20240125_1501.py b/backend/prompt_studio/prompt_studio_core/migrations/0003_merge_20240125_1501.py new file mode 100644 index 000000000..da66a19e0 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/migrations/0003_merge_20240125_1501.py @@ -0,0 +1,15 @@ +# Generated by Django 4.2.1 on 2024-01-25 15:01 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("prompt_studio_core", "0002_alter_customtool_output"), + ( + "prompt_studio_core", + "0002_remove_customtool_updated_at_customtool_modified_at", + ), + ] + + operations = [] diff --git a/backend/prompt_studio/prompt_studio_core/migrations/__init__.py b/backend/prompt_studio/prompt_studio_core/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/prompt_studio/prompt_studio_core/models.py b/backend/prompt_studio/prompt_studio_core/models.py new file mode 100644 index 000000000..4b8128461 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/models.py @@ -0,0 +1,66 @@ +import uuid + +from account.models import User +from django.db import models +from prompt_studio.prompt_profile_manager.models import ProfileManager +from utils.models.base_model import BaseModel + + +class CustomTool(BaseModel): + """Model to store the custom tools designed in the tool studio.""" + + tool_id = models.UUIDField( + primary_key=True, default=uuid.uuid4, editable=False + ) + tool_name = models.TextField(unique=True, blank=False, null=False) + description = models.TextField(blank=False, null=False) + author = models.TextField( + blank=False, + null=False, + db_comment="Specific to the user who created the tool.", + ) + icon = models.TextField( + blank=True, + db_comment="Field to store \ + icon url for the custom tool.", + ) + output = models.TextField( + db_comment="Field to store the output format type.", + blank=True, + ) + log_id = models.UUIDField( + default=uuid.uuid4, + db_comment="Field to store unique log_id for polling", + ) + preamble = models.TextField( + blank=True, db_comment="Preamble to the prompts" + ) + postamble = models.TextField( + blank=True, db_comment="Appended as postable to prompts." + ) + default_profile = models.ForeignKey( + ProfileManager, + on_delete=models.SET_NULL, + related_name="default_profile", + null=True, + blank=True, + ) + prompt_grammer = models.JSONField( + null=True, blank=True, db_comment="Synonymous words used in prompt" + ) + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="tool_created_by", + null=True, + blank=True, + editable=False, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="tool_modified_by", + null=True, + blank=True, + editable=False, + ) diff --git a/backend/prompt_studio/prompt_studio_core/prompt_ide_base_tool.py b/backend/prompt_studio/prompt_studio_core/prompt_ide_base_tool.py new file mode 100644 index 000000000..d1ea56510 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/prompt_ide_base_tool.py @@ -0,0 +1,44 @@ +import os + +from account.models import PlatformKey +from prompt_studio.prompt_studio_core.constants import LogLevel, ToolStudioKeys +from unstract.sdk.tool.stream import StreamMixin + + +class PromptIdeBaseTool(StreamMixin): + def __init__( + self, log_level: LogLevel = LogLevel.INFO, org_id: str = "" + ) -> None: + """ + Args: + tool (UnstractAbstractTool): Instance of UnstractAbstractTool + Notes: + - PLATFORM_SERVICE_API_KEY environment variable is required. + """ + self.log_level = log_level + self.org_id = org_id + super().__init__(log_level=log_level) + + def get_env_or_die(self, env_key: str) -> str: + """Returns the value of an env variable. + + If its empty or None, raises an error and exits + + Args: + env_key (str): Key to retrieve + + Returns: + str: Value of the env + """ + # HACK: Adding platform key for multitenancy + if env_key == ToolStudioKeys.PLATFORM_SERVICE_API_KEY: + platform_key = PlatformKey.objects.get(organization=self.org_id) + key: str = str(platform_key.key) + return key + else: + env_value = os.environ.get(env_key) + if env_value is None or env_value == "": + self.stream_error_and_exit( + f"Env variable {env_key} is required" + ) + return env_value # type:ignore diff --git a/backend/prompt_studio/prompt_studio_core/prompt_studio_helper.py b/backend/prompt_studio/prompt_studio_core/prompt_studio_helper.py new file mode 100644 index 000000000..3e7818751 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/prompt_studio_helper.py @@ -0,0 +1,403 @@ +import json +import logging +import os +from pathlib import Path +from typing import Any, Optional + +from account.models import Organization +from account.organization import OrganizationService +from django.conf import settings +from file_management.file_management_helper import FileManagerHelper +from prompt_studio.prompt_profile_manager.models import ProfileManager +from prompt_studio.prompt_studio.models import ToolStudioPrompt +from prompt_studio.prompt_studio_core.constants import LogLevels +from prompt_studio.prompt_studio_core.constants import ( + ToolStudioPromptKeys as TSPKeys, +) +from prompt_studio.prompt_studio_core.exceptions import ( + AnswerFetchError, + DefaultProfileError, + IndexingError, + OutputSaveError, + PromptNotValid, + ToolNotValid, +) +from prompt_studio.prompt_studio_core.models import CustomTool +from prompt_studio.prompt_studio_core.prompt_ide_base_tool import ( + PromptIdeBaseTool, +) +from unstract.sdk.constants import LogLevel +from unstract.sdk.index import ToolIndex +from unstract.sdk.prompt import PromptTool +from unstract.sdk.utils.tool_utils import ToolUtils + +from unstract.core.pubsub_helper import LogHelper as stream_log + +CHOICES_JSON = "/static/select_choices.json" + +logger = logging.getLogger(__name__) + + +class PromptStudioHelper: + """Helper class for Custom tool operations.""" + + @staticmethod + def get_select_fields() -> dict[str, Any]: + """Method to fetch dropdown field values for frontend. + + Returns: + dict[str, Any]: Dict for dropdown data + """ + f = open(f"{os.path.dirname(__file__)}{CHOICES_JSON}") + choices = f.read() + f.close() + response: dict[str, Any] = json.loads(choices) + return response + + @staticmethod + def _fetch_prompt_from_id(id: str) -> ToolStudioPrompt: + """Internal function used to fetch prompt from ID. + + Args: + id (_type_): UUID of the prompt + + Returns: + ToolStudioPrompt: Instance of the model + """ + prompt_instance: ToolStudioPrompt = ToolStudioPrompt.objects.get(pk=id) + return prompt_instance + + @staticmethod + def fetch_prompt_from_tool(tool_id: str) -> list[ToolStudioPrompt]: + """Internal function used to fetch mapped prompts from ToolID. + + Args: + tool_id (_type_): UUID of the tool + + Returns: + List[ToolStudioPrompt]: List of instance of the model + """ + prompt_instances: list[ + ToolStudioPrompt + ] = ToolStudioPrompt.objects.filter(tool_id=tool_id) + return prompt_instances + + @staticmethod + def index_document( + tool_id: str, file_name: str, org_id: str, user_id: str + ) -> Any: + """Method to index a document. + + Args: + tool_id (str):Id of the tool + file_name (str): File to parse + + Raises: + ToolNotValid + IndexingError + """ + tool: CustomTool = CustomTool.objects.get(pk=tool_id) + default_profile: Optional[ProfileManager] = tool.default_profile + if not default_profile: + raise DefaultProfileError() + file_path = FileManagerHelper.handle_sub_directory_for_tenants( + org_id=org_id, + user_id=user_id, + tool_id=tool_id, + is_create=False, + ) + file_path = str(Path(file_path) / file_name) + stream_log.publish( + tool_id, + stream_log.log( + stage=LogLevels.RUN, + level=LogLevels.INFO, + message=f"Invoking indexing for {tool_id}", + ), + ) + if not tool: + logger.error(f"No tool instance found for the ID {tool_id}") + raise ToolNotValid() + + stream_log.publish( + tool_id, + stream_log.log( + stage=LogLevels.RUN, + level=LogLevels.INFO, + message=f"Calling prompt service for\ + indexing the doc {file_name}", + ), + ) + logger.info( + f"Invoking indexing in prompt service for the tool {tool_id}" + ) + doc_id = PromptStudioHelper.dynamic_indexer( + profile_manager=default_profile, + tool_id=tool_id, + file_name=file_path, + org_id=org_id, + ) + logger.info(f"Indexing done sucessfully for {file_name}") + stream_log.publish( + tool_id, + stream_log.log( + stage=LogLevels.RUN, + level=LogLevels.INFO, + message=f"Indexing successful for the file: {file_name}", + ), + ) + return doc_id + + @staticmethod + def prompt_responder( + id: str, tool_id: str, file_name: str, org_id: str, user_id: str + ) -> Any: + """Execute chain/single run of the prompts. Makes a call to prompt + service and returns the dict of response. + + Args: + id (str): ID of the prompt + tool_id (str): ID of tool created in prompt studio + file_name (str): Name of the file uploaded + org_id (str): Organization ID + user_id (str): User's ID + + Raises: + PromptNotValid: If a prompt could not be queried from the DB + AnswerFetchError: Error from prompt-service + + Returns: + Any: Dictionary containing the response from prompt-service + """ + logger.info(f"Invoking prompt responser for prompt {id}") + file_path = FileManagerHelper.handle_sub_directory_for_tenants( + org_id=org_id, + user_id=user_id, + tool_id=tool_id, + is_create=False, + ) + file_path = str(Path(file_path) / file_name) + if id and tool_id: + logger.info("Executing in single prompt mode") + try: + prompt_instance = PromptStudioHelper._fetch_prompt_from_id(id) + prompts: list[ToolStudioPrompt] = [] + prompts.append(prompt_instance) + tool: CustomTool = prompt_instance.tool_id + stream_log.publish( + tool.tool_id, + stream_log.log( + stage=LogLevels.RUN, + level=LogLevels.INFO, + message=f"Executing single prompt \ + {id} of tool {tool.tool_id}", + ), + ) + if not prompt_instance: + logger.error(f"Prompt id {id} does not have any data in db") + raise PromptNotValid() + except Exception as exc: + logger.error(f"Error while fetching prompt {exc}") + raise AnswerFetchError() + stream_log.publish( + tool.tool_id, + stream_log.log( + stage=LogLevels.RUN, + level=LogLevels.INFO, + message=f"Prompt instance fetched \ + for {id} of tool {tool.tool_id}", + ), + ) + stream_log.publish( + tool.tool_id, + stream_log.log( + stage=LogLevels.RUN, + level=LogLevels.INFO, + message=f"Invoking prompt service for\ + {id} of tool {tool.tool_id}", + ), + ) + logger.info(f"Invoking prompt service for prompt id {id}") + org: Optional[ + Organization + ] = OrganizationService.get_organization_by_org_id(org_id=org_id) + response = PromptStudioHelper._fetch_response( + path=file_path, + tool=tool, + prompts=prompts, + org_id=org.id, # type:ignore + ) + stream_log.publish( + tool.tool_id, + stream_log.log( + stage=LogLevels.RUN, + level=LogLevels.INFO, + message=f"Response fetched sucessfully \ + from platform for prompt {id} of tool {tool.tool_id}", + ), + ) + logger.info(f"Response fetched succesfully for prompt {id}") + return response + + @staticmethod + def _fetch_response( + tool: CustomTool, + path: str, + prompts: list[ToolStudioPrompt], + org_id: str, + ) -> Any: + """Utility function to invoke prompt service. Used internally. + + Args: + tool (CustomTool) + path (str) + prompt (dict) + + Raises: + AnswerFetchError + """ + outputs: list[dict[str, Any]] = [] + + prompt_grammer = tool.prompt_grammer + grammer_dict = {} + grammar_list = [] + + # Adding validations + if prompt_grammer: + for word, synonyms in prompt_grammer.items(): + synonyms = prompt_grammer[word] + grammer_dict[TSPKeys.WORD] = word + grammer_dict[TSPKeys.SYNONYMS] = synonyms + grammar_list.append(grammer_dict) + grammer_dict = {} + for prompt in prompts: + # Not checking reindex here as there might be + # change in Profile Manager + vector_db = str(prompt.profile_manager.vector_store.id) + embedding_model = str(prompt.profile_manager.embedding_model.id) + llm = str(prompt.profile_manager.llm.id) + x2text = str(prompt.profile_manager.x2text.id) + prompt_profile_manager: ProfileManager = prompt.profile_manager + if not prompt_profile_manager: + raise DefaultProfileError() + PromptStudioHelper.dynamic_indexer( + profile_manager=prompt_profile_manager, + file_name=path, + tool_id=str(tool.tool_id), + org_id=org_id, + ) + + output: dict[str, Any] = {} + output[ + TSPKeys.ASSERTION_FAILURE_PROMPT + ] = prompt.assertion_failure_prompt + output[TSPKeys.ASSERT_PROMPT] = prompt.assert_prompt + output[TSPKeys.IS_ASSERT] = prompt.is_assert + output[TSPKeys.PROMPT] = prompt.prompt + output[TSPKeys.ACTIVE] = prompt.active + output[TSPKeys.CHUNK_SIZE] = prompt.profile_manager.chunk_size + output[TSPKeys.VECTOR_DB] = vector_db + output[TSPKeys.EMBEDDING] = embedding_model + output[TSPKeys.CHUNK_OVERLAP] = prompt.profile_manager.chunk_overlap + output[TSPKeys.LLM] = llm + output[TSPKeys.PREAMBLE] = tool.preamble + output[TSPKeys.POSTAMBLE] = tool.postamble + output[TSPKeys.GRAMMAR] = grammar_list + output[TSPKeys.TYPE] = prompt.enforce_type + output[TSPKeys.NAME] = prompt.prompt_key + output[ + TSPKeys.RETRIEVAL_STRATEGY + ] = prompt.profile_manager.retrieval_strategy + output[ + TSPKeys.SIMILARITY_TOP_K + ] = prompt.profile_manager.similarity_top_k + output[TSPKeys.SECTION] = prompt.profile_manager.section + output[TSPKeys.X2TEXT_ADAPTER] = x2text + + # Eval settings for the prompt + output[TSPKeys.EVAL_SETTINGS] = {} + output[TSPKeys.EVAL_SETTINGS][ + TSPKeys.EVAL_SETTINGS_EVALUATE + ] = prompt.evaluate + output[TSPKeys.EVAL_SETTINGS][TSPKeys.EVAL_SETTINGS_MONITOR_LLM] = [ + llm + ] + output[TSPKeys.EVAL_SETTINGS][ + TSPKeys.EVAL_SETTINGS_EXCLUDE_FAILED + ] = False + for attr in dir(prompt): + if attr.startswith(TSPKeys.EVAL_METRIC_PREFIX): + attr_val = getattr(prompt, attr) + output[TSPKeys.EVAL_SETTINGS][attr] = attr_val + + outputs.append(output) + + tool_id = str(tool.tool_id) + + file_hash = ToolUtils.get_hash_from_file(file_path=path) + + payload = { + TSPKeys.OUTPUTS: outputs, + TSPKeys.TOOL_ID: tool_id, + TSPKeys.FILE_NAME: path, + TSPKeys.FILE_HASH: file_hash, + } + + util = PromptIdeBaseTool(log_level=LogLevel.INFO, org_id=org_id) + + responder = PromptTool( + tool=util, + prompt_host=settings.PROMPT_HOST, + prompt_port=settings.PROMPT_PORT, + ) + + answer = responder.answer_prompt(payload) + # TODO: Make use of dataclasses + if answer["status"] == "ERROR": + raise AnswerFetchError() + output_response = json.loads(answer["structure_output"]) + + # persist output + try: + for key in output_response: + if TSPKeys.EVAL_RESULT_DELIM not in key: + persisted_prompt = ToolStudioPrompt.objects.get( + prompt_key=key + ) + persisted_prompt.output = output_response[key] or "" + persisted_prompt.save() + except Exception as e: + logger.error(f"Exception while saving prompt output: {e}") + raise OutputSaveError() + return output_response + + @staticmethod + def dynamic_indexer( + profile_manager: ProfileManager, + tool_id: str, + file_name: str, + org_id: str, + ) -> str: + try: + util = PromptIdeBaseTool(log_level=LogLevel.INFO, org_id=org_id) + tool_index = ToolIndex(tool=util) + except Exception as e: + logger.error(f"Error while instatiating SDKs {e}") + raise IndexingError() + embedding_model = str(profile_manager.embedding_model.id) + vector_db = str(profile_manager.vector_store.id) + x2text_adapter = str(profile_manager.x2text.id) + file_hash = ToolUtils.get_hash_from_file(file_path=file_name) + return str( + tool_index.index_file( + tool_id=tool_id, + embedding_type=embedding_model, + vector_db=vector_db, + x2text_adapter=x2text_adapter, + file_path=file_name, + file_hash=file_hash, + chunk_size=profile_manager.chunk_size, + chunk_overlap=profile_manager.chunk_overlap, + reindex=profile_manager.reindex, + ) + ) diff --git a/backend/prompt_studio/prompt_studio_core/serializers.py b/backend/prompt_studio/prompt_studio_core/serializers.py new file mode 100644 index 000000000..af5fada93 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/serializers.py @@ -0,0 +1,48 @@ +import logging +from typing import Any + +from backend.serializers import AuditSerializer +from prompt_studio.prompt_studio.models import ToolStudioPrompt +from prompt_studio.prompt_studio.serializers import ToolStudioPromptSerializer +from prompt_studio.prompt_studio_core.constants import ToolStudioKeys as TSKeys +from rest_framework import serializers + +from .models import CustomTool + +logger = logging.getLogger(__name__) + + +class CustomToolSerializer(AuditSerializer): + class Meta: + model = CustomTool + fields = "__all__" + + def to_representation(self, instance): # type: ignore + data = super().to_representation(instance) + try: + prompt_instance: ToolStudioPrompt = ToolStudioPrompt.objects.filter( + tool_id=data.get(TSKeys.TOOL_ID) + ).order_by("sequence_number") + data[TSKeys.PROMPTS] = [] + output: list[Any] = [] + # Appending prompt instances of the tool for FE Processing + if prompt_instance.count() != 0: + for prompt in prompt_instance: + prompt_serializer = ToolStudioPromptSerializer(prompt) + output.append(prompt_serializer.data) + data[TSKeys.PROMPTS] = output + except Exception as e: + logger.error(f"Error occured while appending prompts {e}") + return data + return data + + +class PromptStudioIndexSerializer(serializers.Serializer): + file_name = serializers.CharField() + tool_id = serializers.CharField() + + +class PromptStudioResponseSerializer(serializers.Serializer): + file_name = serializers.CharField() + tool_id = serializers.CharField() + id = serializers.CharField() diff --git a/backend/prompt_studio/prompt_studio_core/static/select_choices.json b/backend/prompt_studio/prompt_studio_core/static/select_choices.json new file mode 100644 index 000000000..1e3746674 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/static/select_choices.json @@ -0,0 +1,34 @@ +{ + "combined_output": + { + "JSON":"JSON", + "YAML":"YAML" + }, + "choose_llm":{ + "AZURE":"Azure OpenAI" + }, + "output_type":{ + "string":"Text", + "number":"number", + "email":"email", + "date":"date", + "boolean":"boolean", + "json":"json" + }, + "output_processing":{ + "DEFAULT":"Default" + }, + "embedding":{ + "azure_openai_embedding":"azure_openai_embedding", + "openai_embedding":"openai_embedding" + }, + "retrieval_strategy":{ + "simple":"simple", + "subquestion":"subquestion", + "vector+keyword":"vector+keyword" + }, + "vector_store":{ + "Postgres pg_vector":"Postgres pg_vector", + "qdrant":"qdrant" + } +} diff --git a/backend/prompt_studio/prompt_studio_core/urls.py b/backend/prompt_studio/prompt_studio_core/urls.py new file mode 100644 index 000000000..6469f6236 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/urls.py @@ -0,0 +1,59 @@ +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns + +from .views import PromptStudioCoreView + +prompt_studio_list = PromptStudioCoreView.as_view( + {"get": "list", "post": "create"} +) +prompt_studio_detail = PromptStudioCoreView.as_view( + { + "get": "retrieve", + "put": "update", + "patch": "partial_update", + "delete": "destroy", + } +) +prompt_studio_choices = PromptStudioCoreView.as_view( + {"get": "get_select_choices"} +) +prompt_studio_prompt_index = PromptStudioCoreView.as_view( + {"post": "index_document"} +) +prompt_studio_prompt_response = PromptStudioCoreView.as_view( + {"post": "fetch_response"} +) +prompt_studio_adapter_choices = PromptStudioCoreView.as_view( + {"get": "get_adapter_choices"} +) + +urlpatterns = format_suffix_patterns( + [ + path("prompt-studio/", prompt_studio_list, name="prompt-studio-list"), + path( + "prompt-studio//", + prompt_studio_detail, + name="tool-studio-detail", + ), + path( + "prompt-studio/select_choices/", + prompt_studio_choices, + name="prompt-studio-choices", + ), + path( + "prompt-studio/index-document/", + prompt_studio_prompt_index, + name="prompt-studio-prompt-index", + ), + path( + "prompt-studio/fetch_response/", + prompt_studio_prompt_response, + name="prompt-studio-prompt-response", + ), + path( + "prompt-studio/adapter-choices/", + prompt_studio_adapter_choices, + name="prompt-studio-adapter-choices", + ), + ] +) diff --git a/backend/prompt_studio/prompt_studio_core/views.py b/backend/prompt_studio/prompt_studio_core/views.py new file mode 100644 index 000000000..5be5fa54c --- /dev/null +++ b/backend/prompt_studio/prompt_studio_core/views.py @@ -0,0 +1,183 @@ +import logging +from typing import Any, Optional + +from account.custom_exceptions import DuplicateData +from django.db import IntegrityError +from django.db.models import QuerySet +from django.http import HttpRequest +from permissions.permission import IsOwner +from prompt_studio.prompt_studio.exceptions import FilenameMissingError +from prompt_studio.prompt_studio_core.constants import ( + ToolStudioErrors, + ToolStudioKeys, + ToolStudioPromptKeys, +) +from prompt_studio.prompt_studio_core.exceptions import ( + IndexingError, + ToolDeleteError, +) +from prompt_studio.prompt_studio_core.prompt_studio_helper import ( + PromptStudioHelper, +) +from rest_framework import status, viewsets +from rest_framework.decorators import action +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning +from tool_instance.models import ToolInstance +from utils.filtering import FilterHelper + +from .models import CustomTool +from .serializers import CustomToolSerializer, PromptStudioIndexSerializer + +logger = logging.getLogger(__name__) + + +class PromptStudioCoreView(viewsets.ModelViewSet): + """Viewset to handle all Custom tool related operations.""" + + versioning_class = URLPathVersioning + + permission_classes = [IsOwner] + serializer_class = CustomToolSerializer + + def get_queryset(self) -> Optional[QuerySet]: + filter_args = FilterHelper.build_filter_args( + self.request, + ToolStudioKeys.CREATED_BY, + ) + if filter_args: + queryset = CustomTool.objects.filter( + created_by=self.request.user, **filter_args + ) + else: + queryset = CustomTool.objects.filter( + created_by=self.request.user, + ) + return queryset + + def create( + self, request: HttpRequest, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> Response: + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + try: + self.perform_create(serializer) + except IntegrityError: + raise DuplicateData( + f"{ToolStudioErrors.TOOL_NAME_EXISTS}, \ + {ToolStudioErrors.DUPLICATE_API}" + ) + return Response(serializer.data, status=status.HTTP_201_CREATED) + + def destroy( + self, request: Request, *args: tuple[Any], **kwargs: dict[str, Any] + ) -> Response: + instance: CustomTool = self.get_object() + exported_tool_instances_in_use = ToolInstance.objects.filter( + tool_id__exact=instance.prompt_studio_registry.pk + ) + dependent_wfs = set() + for tool_instance in exported_tool_instances_in_use: + dependent_wfs.add(tool_instance.workflow_id) + if len(dependent_wfs) > 0: + logger.info( + f"Cannot destroy custom tool {instance.tool_id}," + f" depended by workflows {dependent_wfs}" + ) + raise ToolDeleteError( + "Failed to delete tool, its used in other workflows. " + "Delete its usages first" + ) + + return super().destroy(request, *args, **kwargs) + + @action(detail=True, methods=["get"]) + def get_select_choices(self, request: HttpRequest) -> Response: + """Method to return all static dropdown field values. + + The field values are retrieved from `./static/select_choices.json`. + + Returns: + Response: Reponse of dropdown dict + """ + try: + select_choices: dict[ + str, Any + ] = PromptStudioHelper.get_select_fields() + return Response(select_choices, status=status.HTTP_200_OK) + except Exception as e: + logger.error(f"Error occured while fetching select fields {e}") + return Response(select_choices, status=status.HTTP_204_NO_CONTENT) + + @action(detail=True, methods=["get"]) + def index_document(self, request: HttpRequest) -> Response: + """API Entry point method to index input file. + + Args: + request (HttpRequest) + + Raises: + IndexingError + ValidationError + + Returns: + Response + """ + serializer = PromptStudioIndexSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + tool_id: str = serializer.validated_data.get( + ToolStudioPromptKeys.TOOL_ID + ) + file_name: str = serializer.validated_data.get( + ToolStudioPromptKeys.FILE_NAME + ) + try: + unique_id = PromptStudioHelper.index_document( + tool_id=tool_id, + file_name=file_name, + org_id=request.org_id, + user_id=request.user.user_id, + ) + if unique_id: + return Response( + {"message": "Document indexed successfully."}, + status=status.HTTP_200_OK, + ) + else: + logger.error( + "Error occured while indexing. Unique ID is not valid." + ) + raise IndexingError() + except Exception as exc: + logger.error(f"Error occured while indexing {exc}") + raise IndexingError() + + @action(detail=True, methods=["post"]) + def fetch_response(self, request: HttpRequest) -> Response: + """API Entry point method to fetch response to prompt. + + Args: + request (HttpRequest): _description_ + + Raises: + FilenameMissingError: _description_ + + Returns: + Response + """ + tool_id: str = request.data.get(ToolStudioPromptKeys.TOOL_ID) + file_name: str = request.data.get(ToolStudioPromptKeys.FILE_NAME) + id: str = request.data.get(ToolStudioPromptKeys.ID) + + if not file_name or file_name == ToolStudioPromptKeys.UNDEFINED: + logger.error("Mandatory field file_name is missing") + raise FilenameMissingError() + response: dict[str, Any] = PromptStudioHelper.prompt_responder( + id=id, + tool_id=tool_id, + file_name=file_name, + org_id=request.org_id, + user_id=request.user.user_id, + ) + return Response(response, status=status.HTTP_200_OK) diff --git a/backend/prompt_studio/prompt_studio_output_manager/__init__.py b/backend/prompt_studio/prompt_studio_output_manager/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/prompt_studio/prompt_studio_output_manager/admin.py b/backend/prompt_studio/prompt_studio_output_manager/admin.py new file mode 100644 index 000000000..00fd98264 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import PromptStudioOutputManager + +admin.site.register(PromptStudioOutputManager) diff --git a/backend/prompt_studio/prompt_studio_output_manager/apps.py b/backend/prompt_studio/prompt_studio_output_manager/apps.py new file mode 100644 index 000000000..055b16d8d --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class PromptStudioOutputManager(AppConfig): + name = "prompt_studio.prompt_studio_output_manager" diff --git a/backend/prompt_studio/prompt_studio_output_manager/constants.py b/backend/prompt_studio/prompt_studio_output_manager/constants.py new file mode 100644 index 000000000..f2cbd9b94 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/constants.py @@ -0,0 +1,5 @@ +class PromptStudioOutputManagerKeys: + TOOL_ID = "tool_id" + PROMPT_ID = "prompt_id" + PROFILE_MANAGER = "profile_manager" + DOC_NAME = "doc_name" diff --git a/backend/prompt_studio/prompt_studio_output_manager/exceptions.py b/backend/prompt_studio/prompt_studio_output_manager/exceptions.py new file mode 100644 index 000000000..63551469e --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/exceptions.py @@ -0,0 +1,7 @@ +from rest_framework.exceptions import APIException + + +class InternalError(APIException): + status_code = 400 + default_detail = "Internal service error." + diff --git a/backend/prompt_studio/prompt_studio_output_manager/migrations/0001_initial.py b/backend/prompt_studio/prompt_studio_output_manager/migrations/0001_initial.py new file mode 100644 index 000000000..726064b17 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/migrations/0001_initial.py @@ -0,0 +1,95 @@ +# Generated by Django 4.2.1 on 2024-02-07 11:20 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + ("prompt_studio_core", "0003_merge_20240125_1501"), + ("prompt_studio", "0003_remove_toolstudioprompt_updated_at_and_more"), + ("prompt_profile_manager", "0003_merge_20240125_0530"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="PromptStudioOutputManager", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "prompt_output_id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ("output", models.CharField(db_comment="Field to store output")), + ( + "created_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="prompt_output_created_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="prompt_output_modified_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "profile_manager", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="prompt_output_linked_prompt", + to="prompt_profile_manager.profilemanager", + ), + ), + ( + "prompt_id", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="prompt_output_linked_prompt", + to="prompt_studio.toolstudioprompt", + ), + ), + ( + "tool_id", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="prompt_ouput_linked_tool", + to="prompt_studio_core.customtool", + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/backend/prompt_studio/prompt_studio_output_manager/migrations/0002_promptstudiooutputmanager_doc_name.py b/backend/prompt_studio/prompt_studio_output_manager/migrations/0002_promptstudiooutputmanager_doc_name.py new file mode 100644 index 000000000..527d0b452 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/migrations/0002_promptstudiooutputmanager_doc_name.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.1 on 2024-02-07 19:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("prompt_studio_output_manager", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="promptstudiooutputmanager", + name="doc_name", + field=models.CharField( + blank=True, + db_comment="Field to store the document name", + editable=False, + null=True, + ), + ), + ] diff --git a/backend/prompt_studio/prompt_studio_output_manager/migrations/0003_alter_promptstudiooutputmanager_doc_name.py b/backend/prompt_studio/prompt_studio_output_manager/migrations/0003_alter_promptstudiooutputmanager_doc_name.py new file mode 100644 index 000000000..515012c06 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/migrations/0003_alter_promptstudiooutputmanager_doc_name.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.1 on 2024-02-07 19:53 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + dependencies = [ + ("prompt_studio_output_manager", "0002_promptstudiooutputmanager_doc_name"), + ] + + operations = [ + migrations.AlterField( + model_name="promptstudiooutputmanager", + name="doc_name", + field=models.CharField( + db_comment="Field to store the document name", + default=django.utils.timezone.now, + editable=False, + ), + preserve_default=False, + ), + ] diff --git a/backend/prompt_studio/prompt_studio_output_manager/migrations/0004_alter_promptstudiooutputmanager_doc_name.py b/backend/prompt_studio/prompt_studio_output_manager/migrations/0004_alter_promptstudiooutputmanager_doc_name.py new file mode 100644 index 000000000..b51b80233 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/migrations/0004_alter_promptstudiooutputmanager_doc_name.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.1 on 2024-02-07 20:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ( + "prompt_studio_output_manager", + "0003_alter_promptstudiooutputmanager_doc_name", + ), + ] + + operations = [ + migrations.AlterField( + model_name="promptstudiooutputmanager", + name="doc_name", + field=models.CharField(db_comment="Field to store the document name"), + ), + ] diff --git a/backend/prompt_studio/prompt_studio_output_manager/migrations/0005_alter_promptstudiooutputmanager_profile_manager_and_more.py b/backend/prompt_studio/prompt_studio_output_manager/migrations/0005_alter_promptstudiooutputmanager_profile_manager_and_more.py new file mode 100644 index 000000000..61067a382 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/migrations/0005_alter_promptstudiooutputmanager_profile_manager_and_more.py @@ -0,0 +1,52 @@ +# Generated by Django 4.2.1 on 2024-02-07 20:53 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ("prompt_studio_core", "0003_merge_20240125_1501"), + ("prompt_studio", "0003_remove_toolstudioprompt_updated_at_and_more"), + ("prompt_profile_manager", "0003_merge_20240125_0530"), + ( + "prompt_studio_output_manager", + "0004_alter_promptstudiooutputmanager_doc_name", + ), + ] + + operations = [ + migrations.AlterField( + model_name="promptstudiooutputmanager", + name="profile_manager", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="prompt_output_linked_prompt", + to="prompt_profile_manager.profilemanager", + ), + ), + migrations.AlterField( + model_name="promptstudiooutputmanager", + name="prompt_id", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="prompt_output_linked_prompt", + to="prompt_studio.toolstudioprompt", + ), + ), + migrations.AlterField( + model_name="promptstudiooutputmanager", + name="tool_id", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="prompt_ouput_linked_tool", + to="prompt_studio_core.customtool", + ), + ), + ] diff --git a/backend/prompt_studio/prompt_studio_output_manager/migrations/0006_alter_promptstudiooutputmanager_output.py b/backend/prompt_studio/prompt_studio_output_manager/migrations/0006_alter_promptstudiooutputmanager_output.py new file mode 100644 index 000000000..ca898210f --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/migrations/0006_alter_promptstudiooutputmanager_output.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.1 on 2024-02-13 12:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ( + "prompt_studio_output_manager", + "0005_alter_promptstudiooutputmanager_profile_manager_and_more", + ), + ] + + operations = [ + migrations.AlterField( + model_name="promptstudiooutputmanager", + name="output", + field=models.CharField( + blank=True, db_comment="Field to store output", null=True + ), + ), + ] diff --git a/backend/prompt_studio/prompt_studio_output_manager/migrations/__init__.py b/backend/prompt_studio/prompt_studio_output_manager/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/prompt_studio/prompt_studio_output_manager/models.py b/backend/prompt_studio/prompt_studio_output_manager/models.py new file mode 100644 index 000000000..3392bd5a2 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/models.py @@ -0,0 +1,67 @@ +import uuid + +from account.models import User +from django.db import models +from prompt_studio.prompt_profile_manager.models import ProfileManager +from prompt_studio.prompt_studio.models import ToolStudioPrompt +from prompt_studio.prompt_studio_core.models import CustomTool +from utils.models.base_model import BaseModel + + +class PromptStudioOutputManager(BaseModel): + """Data model to handle output persisitance for Project. + + By default the tools will be added to private tool hub. + """ + + prompt_output_id = models.UUIDField( + primary_key=True, default=uuid.uuid4, editable=False + ) + + output = models.CharField( + db_comment="Field to store output", editable=True, null=True, blank=True + ) + + doc_name = models.CharField( + db_comment="Field to store the document name", + editable=True, + ) + + tool_id = models.ForeignKey( + CustomTool, + on_delete=models.SET_NULL, + related_name="prompt_ouput_linked_tool", + null=True, + blank=True, + ) + prompt_id = models.ForeignKey( + ToolStudioPrompt, + on_delete=models.SET_NULL, + related_name="prompt_output_linked_prompt", + null=True, + blank=True, + ) + profile_manager = models.ForeignKey( + ProfileManager, + on_delete=models.SET_NULL, + related_name="prompt_output_linked_prompt", + null=True, + blank=True, + ) + + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="prompt_output_created_by", + null=True, + blank=True, + editable=False, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="prompt_output_modified_by", + null=True, + blank=True, + editable=False, + ) diff --git a/backend/prompt_studio/prompt_studio_output_manager/serializers.py b/backend/prompt_studio/prompt_studio_output_manager/serializers.py new file mode 100644 index 000000000..c0a0af5bd --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/serializers.py @@ -0,0 +1,10 @@ +from backend.serializers import AuditSerializer + +from .models import PromptStudioOutputManager + + +class PromptStudioOutputSerializer(AuditSerializer): + class Meta: + model = PromptStudioOutputManager + fields = "__all__" + diff --git a/backend/prompt_studio/prompt_studio_output_manager/urls.py b/backend/prompt_studio/prompt_studio_output_manager/urls.py new file mode 100644 index 000000000..5f6f76ca7 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/urls.py @@ -0,0 +1,17 @@ +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns + +from .views import PromptStudioOutputView + +prompt_doc_list = PromptStudioOutputView.as_view({"get": "list", "post": "create"}) +prompt_doc_detail = PromptStudioOutputView.as_view( + {"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"} +) + +urlpatterns = format_suffix_patterns( + [ + path("prompt-output/", prompt_doc_list, name="prompt-doc-list"), + path("prompt-output//", prompt_doc_detail, name="prompt-doc-detail"), + + ] +) diff --git a/backend/prompt_studio/prompt_studio_output_manager/views.py b/backend/prompt_studio/prompt_studio_output_manager/views.py new file mode 100644 index 000000000..f9f743a3c --- /dev/null +++ b/backend/prompt_studio/prompt_studio_output_manager/views.py @@ -0,0 +1,37 @@ +import logging +from typing import Optional + +from django.db.models import QuerySet +from prompt_studio.prompt_studio_output_manager.constants import ( + PromptStudioOutputManagerKeys, +) +from prompt_studio.prompt_studio_output_manager.serializers import ( + PromptStudioOutputSerializer, +) +from rest_framework import viewsets +from rest_framework.versioning import URLPathVersioning +from utils.filtering import FilterHelper + +from .models import PromptStudioOutputManager + +logger = logging.getLogger(__name__) + + +class PromptStudioOutputView(viewsets.ModelViewSet): + versioning_class = URLPathVersioning + queryset = PromptStudioOutputManager.objects.all() + serializer_class = PromptStudioOutputSerializer + + def get_queryset(self) -> Optional[QuerySet]: + filter_args = FilterHelper.build_filter_args( + self.request, + PromptStudioOutputManagerKeys.TOOL_ID, + PromptStudioOutputManagerKeys.PROMPT_ID, + PromptStudioOutputManagerKeys.PROFILE_MANAGER, + PromptStudioOutputManagerKeys.DOC_NAME, + ) + if filter_args: + queryset = PromptStudioOutputManager.objects.filter(**filter_args) + else: + queryset = PromptStudioOutputManager.objects.all() + return queryset diff --git a/backend/prompt_studio/prompt_studio_registry/__init__.py b/backend/prompt_studio/prompt_studio_registry/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/prompt_studio/prompt_studio_registry/admin.py b/backend/prompt_studio/prompt_studio_registry/admin.py new file mode 100644 index 000000000..9f6bdeb83 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import PromptStudioRegistry + +admin.site.register(PromptStudioRegistry) diff --git a/backend/prompt_studio/prompt_studio_registry/apps.py b/backend/prompt_studio/prompt_studio_registry/apps.py new file mode 100644 index 000000000..5bd8c61d0 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class PromptStudioRegistry(AppConfig): + name = "prompt_studio.prompt_studio_registry" diff --git a/backend/prompt_studio/prompt_studio_registry/constants.py b/backend/prompt_studio/prompt_studio_registry/constants.py new file mode 100644 index 000000000..f33deb303 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/constants.py @@ -0,0 +1,105 @@ +class PromptStudioRegistryKeys: + CREATED_BY = "created_by" + TOOL_ID = "tool_id" + NUMBER = "Number" + FLOAT = "Float" + PG_VECTOR = "Postgres pg_vector" + ANSWERS = "answers" + UNIQUE_FILE_ID = "unique_file_id" + PROMPT_REGISTRY_ID = "prompt_registry_id" + FILE_NAME = "file_name" + UNDEFINED = "undefined" + + +class PromptStudioRegistryErrors: + SERIALIZATION_FAILED = "Data Serialization Failed." + DUPLICATE_API = "It appears that a duplicate call may have been made." + CUSTOM_TOOL_EXISTS = ( + "Custom tool with similiar configuration already exists" + ) + + +class LogLevels: + INFO = "INFO" + ERROR = "ERROR" + DEBUG = "DEBUG" + RUN = "RUN" + + +# TODO: Update prompt studio constants to have a single source of truth +class JsonSchemaKey: + TYPE = "type" + TITLE = "title" + DEFAULT = "default" + ENUM = "enum" + DESCRIPTION = "description" + REQUIRED = "required" + STRING = "string" + PROCESSOR_TO_USE = "Processor to use" + AZURE_OPEN_AI = "Azure OpenAI" + PROPERTIES = "properties" + DISPLAY_NAME = "display_name" + FUNCTION_NAME = "function_name" + PARAMETERS = "parameters" + VERSIONS = "versions" + OUTPUT_TYPE = "output_type" + INPUT_TYPE = "input_type" + IS_CACHABLE = "is_cacheable" + REQUIRES = "requires" + DEFAULT_DESCRIPTION_PROCESSOR = "Use Unstract processor \ + if you do not want to use a cloud provider for privacy reasons" + NAME = "name" + ACTIVE = "active" + PROMPT = "prompt" + CHUNK_SIZE = "chunk-size" + PROMPTX = "promptx" + VECTOR_DB = "vector-db" + EMBEDDING = "embedding" + X2TEXT_ADAPTER = "x2text_adapter" + CHUNK_OVERLAP = "chunk-overlap" + LLM = "llm" + IS_ASSERT = "is_assert" + ASSERTION_FAILURE_PROMPT = "assertion_failure_prompt" + RETRIEVAL_STRATEGY = "retrieval-strategy" + SIMPLE = "simple" + VECTOR_KEYWORD = "vector+keyword" + SUBQUESTION = "subquestion" + TYPE = "type" + NUMBER = "number" + EMAIL = "email" + DATE = "date" + BOOLEAN = "boolean" + JSON = "json" + PREAMBLE = "preamble" + SIMILARITY_TOP_K = "similarity-top-k" + PROMPT_TOKENS = "prompt_tokens" + COMPLETION_TOKENS = "completion_tokens" + TOTAL_TOKENS = "total_tokens" + RESPONSE = "response" + POSTAMBLE = "postamble" + GRAMMAR = "grammar" + WORD = "word" + SYNONYMS = "synonyms" + OUTPUTS = "outputs" + ASSERT_PROMPT = "assert_prompt" + SECTION = "section" + DEFAULT = "default" + AUTHOR = "author" + ICON = "icon" + REINDEX = "reindex" + TOOL_ID = "tool_id" + EMBEDDING_SUFFIX = "embedding_suffix" + FUNCTION_NAME = "function_name" + PROMPT_REGISTRY_ID = "prompt_registry_id" + + +class SpecKey: + PROCESSOR = "processor" + SPEC = "spec" + OUTPUT_FOLDER = "outputFolder" + CREATE_OUTPUT_DOCUMENT = "createOutputDocument" + USE_CACHE = "useCache" + EMBEDDING_TRANSFORMER = "embeddingTransformer" + VECTOR_STORE = "vectorstore" + OUTPUT_TYPE = "outputType" + OUTPUT_PROCESSING = "outputProcessing" diff --git a/backend/prompt_studio/prompt_studio_registry/exceptions.py b/backend/prompt_studio/prompt_studio_registry/exceptions.py new file mode 100644 index 000000000..b46dad0eb --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/exceptions.py @@ -0,0 +1,32 @@ +from rest_framework.exceptions import APIException + + +class InternalError(APIException): + status_code = 500 + default_detail = "Internal service error." + + +class ToolDoesNotExist(APIException): + status_code = 500 + default_detail = "Tool does not exist." + + +class ToolSaveError(APIException): + status_code = 500 + default_detail = "Error while saving the tool." + + +class MandatoryFieldMissingError(APIException): + status_code = 400 + default_detail = "Mandatory field missing." + + +class ProfileErrors(APIException): + status_code = 400 + default_detail = f"""Looks like some default values are + not selected. Please check profile managers.""" + + +class DuplicateData(APIException): + status_code = 400 + default_detail = "Duplicate Data" diff --git a/backend/prompt_studio/prompt_studio_registry/fields.py b/backend/prompt_studio/prompt_studio_registry/fields.py new file mode 100644 index 000000000..6e790fb3c --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/fields.py @@ -0,0 +1,29 @@ +import logging + +from django.db import models + +logger = logging.getLogger(__name__) + + +class ToolPropertyJSONField(models.JSONField): + def from_db_value(self, value, expression, connection): # type: ignore + metadata = super().from_db_value(value, expression, connection) + return metadata + + +class ToolSpecJSONField(models.JSONField): + def from_db_value(self, value, expression, connection): # type: ignore + metadata = super().from_db_value(value, expression, connection) + return metadata + + +class ToolVariablesJSONField(models.JSONField): + def from_db_value(self, value, expression, connection): # type: ignore + metadata = super().from_db_value(value, expression, connection) + return metadata + + +class ToolMetadataJSONField(models.JSONField): + def from_db_value(self, value, expression, connection): # type: ignore + metadata = super().from_db_value(value, expression, connection) + return metadata diff --git a/backend/prompt_studio/prompt_studio_registry/migrations/0001_initial.py b/backend/prompt_studio/prompt_studio_registry/migrations/0001_initial.py new file mode 100644 index 000000000..cf140e76c --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/migrations/0001_initial.py @@ -0,0 +1,87 @@ +# Generated by Django 4.2.1 on 2024-01-20 08:04 + +import uuid + +import django.db.models.deletion +import prompt_studio.prompt_studio_registry.fields +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="PromptStudioRegistry", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "prompt_registry_id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "tool_property", + prompt_studio.prompt_studio_registry.fields.ToolPropertyJSONField( + db_column="tool_property", default=dict + ), + ), + ( + "tool_spec", + prompt_studio.prompt_studio_registry.fields.ToolSpecJSONField( + db_column="tool_spec", default=dict + ), + ), + ( + "tool_metadata", + prompt_studio.prompt_studio_registry.fields.ToolMetadataJSONField( + db_column="tool_metadata", default=dict + ), + ), + ( + "icon", + models.CharField( + db_comment="Tool icon in svg format", editable=False + ), + ), + ("url", models.CharField(editable=False)), + ("name", models.CharField(default="", editable=False)), + ("description", models.CharField(default="", editable=False)), + ( + "created_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="prompt_registry_created_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="prompt_registry_modified_by", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/backend/prompt_studio/prompt_studio_registry/migrations/0002_remove_promptstudioregistry_updated_at_and_more.py b/backend/prompt_studio/prompt_studio_registry/migrations/0002_remove_promptstudioregistry_updated_at_and_more.py new file mode 100644 index 000000000..1410b7e14 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/migrations/0002_remove_promptstudioregistry_updated_at_and_more.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.1 on 2024-01-23 19:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("prompt_studio_registry", "0001_initial"), + ] + + operations = [ + migrations.RemoveField( + model_name="promptstudioregistry", + name="updated_at", + ), + migrations.AddField( + model_name="promptstudioregistry", + name="modified_at", + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/backend/prompt_studio/prompt_studio_registry/migrations/0003_alter_promptstudioregistry_tool_metadata_and_more.py b/backend/prompt_studio/prompt_studio_registry/migrations/0003_alter_promptstudioregistry_tool_metadata_and_more.py new file mode 100644 index 000000000..81b2d00f8 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/migrations/0003_alter_promptstudioregistry_tool_metadata_and_more.py @@ -0,0 +1,43 @@ +# Generated by Django 4.2.1 on 2024-02-01 11:58 + +import prompt_studio.prompt_studio_registry.fields +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ( + "prompt_studio_registry", + "0002_remove_promptstudioregistry_updated_at_and_more", + ), + ] + + operations = [ + migrations.AlterField( + model_name="promptstudioregistry", + name="tool_metadata", + field=prompt_studio.prompt_studio_registry.fields.ToolMetadataJSONField( + db_column="tool_metadata", + db_comment="Metadata from Prompt Studio", + default=dict, + ), + ), + migrations.AlterField( + model_name="promptstudioregistry", + name="tool_property", + field=prompt_studio.prompt_studio_registry.fields.ToolPropertyJSONField( + db_column="tool_property", + db_comment="PROPERTIES of the tool", + default=dict, + ), + ), + migrations.AlterField( + model_name="promptstudioregistry", + name="tool_spec", + field=prompt_studio.prompt_studio_registry.fields.ToolSpecJSONField( + db_column="tool_spec", + db_comment="SPEC of the tool", + default=dict, + ), + ), + ] diff --git a/backend/prompt_studio/prompt_studio_registry/migrations/0004_promptstudioregistry_custom_tool.py b/backend/prompt_studio/prompt_studio_registry/migrations/0004_promptstudioregistry_custom_tool.py new file mode 100644 index 000000000..1bdee594e --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/migrations/0004_promptstudioregistry_custom_tool.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.1 on 2024-02-06 03:55 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("prompt_studio_core", "0003_merge_20240125_1501"), + ( + "prompt_studio_registry", + "0003_alter_promptstudioregistry_tool_metadata_and_more", + ), + ] + + operations = [ + migrations.AddField( + model_name="promptstudioregistry", + name="custom_tool", + field=models.OneToOneField( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="prompt_studio_registry", + to="prompt_studio_core.customtool", + ), + ) + ] diff --git a/backend/prompt_studio/prompt_studio_registry/migrations/0005_delete_corrupt_tool_instance.py b/backend/prompt_studio/prompt_studio_registry/migrations/0005_delete_corrupt_tool_instance.py new file mode 100644 index 000000000..d8d47e3f6 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/migrations/0005_delete_corrupt_tool_instance.py @@ -0,0 +1,30 @@ +# Generated by Django 4.2.1 on 2024-02-06 19:36 +from django.db import migrations, transaction +from tool_instance.exceptions import ToolDoesNotExist +from tool_instance.models import ToolInstance +from tool_instance.tool_processor import ToolProcessor + + +def populate_tool_instances(apps, schema_editor): + ToolInstance = apps.get_model("tool_instance", "ToolInstance") + + # Get all tool instances + tool_instances = ToolInstance.objects.all() + with transaction.atomic(): + # Loop through each tool instance and call the function + for tool_instance in tool_instances: + try: + # Call the function to lookup the tool by tool_id + tool = ToolProcessor.get_tool_by_uid(tool_instance.tool_id) + except ToolDoesNotExist as e: + # Delete the tool_instance since its a stray exported tool + tool_instance.delete() + + +class Migration(migrations.Migration): + dependencies = [ + ("prompt_studio_registry", "0004_promptstudioregistry_custom_tool"), + ("tool_instance", "0001_initial"), + ] + + operations = [migrations.RunPython(populate_tool_instances)] diff --git a/backend/prompt_studio/prompt_studio_registry/migrations/__init__.py b/backend/prompt_studio/prompt_studio_registry/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/prompt_studio/prompt_studio_registry/models.py b/backend/prompt_studio/prompt_studio_registry/models.py new file mode 100644 index 000000000..df52c6856 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/models.py @@ -0,0 +1,74 @@ +import uuid + +from account.models import User +from django.db import models +from prompt_studio.prompt_studio.models import CustomTool +from utils.models.base_model import BaseModel + +from .fields import ( + ToolMetadataJSONField, + ToolPropertyJSONField, + ToolSpecJSONField, +) + + +class PromptStudioRegistry(BaseModel): + """Data model to export JSON fields needed for registering the Custom tool + to the tool registry. + + By default the tools will be added to private tool hub. + """ + + prompt_registry_id = models.UUIDField( + primary_key=True, default=uuid.uuid4, editable=False + ) + name = models.CharField(editable=False, default="") + description = models.CharField(editable=False, default="") + tool_property = ToolPropertyJSONField( + db_column="tool_property", + db_comment="PROPERTIES of the tool", + null=False, + blank=False, + default=dict, + ) + tool_spec = ToolSpecJSONField( + db_column="tool_spec", + db_comment="SPEC of the tool", + null=False, + blank=False, + default=dict, + ) + tool_metadata = ToolMetadataJSONField( + db_column="tool_metadata", + db_comment="Metadata from Prompt Studio", + null=False, + blank=False, + default=dict, + ) + icon = models.CharField( + db_comment="Tool icon in svg format", editable=False + ) + url = models.CharField(editable=False) + custom_tool = models.OneToOneField( + CustomTool, + on_delete=models.CASCADE, + related_name="prompt_studio_registry", + editable=False, + null=True, + ) + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="prompt_registry_created_by", + null=True, + blank=True, + editable=False, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="prompt_registry_modified_by", + null=True, + blank=True, + editable=False, + ) diff --git a/backend/prompt_studio/prompt_studio_registry/prompt_studio_registry_helper.py b/backend/prompt_studio/prompt_studio_registry/prompt_studio_registry_helper.py new file mode 100644 index 000000000..0627e44c4 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/prompt_studio_registry_helper.py @@ -0,0 +1,258 @@ +import logging +from typing import Any, Optional + +from django.conf import settings +from django.db import IntegrityError +from prompt_studio.prompt_studio.models import ToolStudioPrompt +from prompt_studio.prompt_studio_core.models import CustomTool +from prompt_studio.prompt_studio_core.prompt_studio_helper import ( + PromptStudioHelper, +) +from unstract.tool_registry.dto import Properties, Spec, Tool + +from .constants import JsonSchemaKey +from .exceptions import InternalError, ProfileErrors, ToolSaveError +from .models import PromptStudioRegistry +from .serializers import PromptStudioRegistrySerializer + +logger = logging.getLogger(__name__) + + +class PromptStudioRegistryHelper: + """Class to register custom tools to tool studio registry. + + By default the exported tools will be private and will be executed + with the help of a proto tool. + """ + + @staticmethod + def frame_spec(tool: CustomTool) -> Spec: + """Method to return spec of the Custom tool. + + Args: + tool (CustomTool): Saved tool data + + Returns: + dict: spec dict + """ + spec = Spec(title=str(tool.tool_id), description=tool.description) + return spec + + @staticmethod + def frame_properties(tool: CustomTool) -> Properties: + """Method to return properties of the tool. + + Args: + tool (CustomTool): Saved custom tool data. + + Returns: + dict: Properties dict + """ + # TODO: Update for new architecture + tool_props = Properties( + display_name=tool.tool_name, + function_name=str(tool.tool_id), + description=tool.description, + ) + return tool_props + + @staticmethod + def get_tool_by_prompt_registry_id( + prompt_registry_id: str, + ) -> Optional[Tool]: + """Gets the `Tool` associated with a prompt registry ID if it exists. + + Args: + prompt_registry_id (str): Prompt registry ID to fetch for + + Returns: + Optional[Tool]: The `Tool` exported from Prompt Studio + """ + try: + prompt_registry_tool = PromptStudioRegistry.objects.get( + pk=prompt_registry_id + ) + # Suppress all exceptions to allow processing + except Exception as e: + logger.warning( + "Error while fetching for prompt registry " + f"ID {prompt_registry_id}: {e} " + ) + return None + return Tool( + tool_uid=prompt_registry_tool.prompt_registry_id, + properties=Properties.from_dict(prompt_registry_tool.tool_property), + spec=Spec.from_dict(prompt_registry_tool.tool_spec), + icon=prompt_registry_tool.icon, + image_url=settings.STRUCTURE_TOOL_IMAGE_URL, + image_name=settings.STRUCTURE_TOOL_IMAGE_NAME, + image_tag=settings.STRUCTURE_TOOL_IMAGE_TAG, + ) + + @staticmethod + def update_or_create_psr_tool( + custom_tool: CustomTool, + ) -> PromptStudioRegistry: + """Updates or creates the PromptStudioRegistry record. + + This appears as a separate tool in the workflow and is mapped + 1:1 with the `CustomTool`. + + Args: + tool_id (str): ID of the custom tool. + + Raises: + ToolSaveError + InternalError + + Returns: + obj: PromptStudioRegistry instance that was updated or created + """ + try: + properties: Properties = ( + PromptStudioRegistryHelper.frame_properties(tool=custom_tool) + ) + spec: Spec = PromptStudioRegistryHelper.frame_spec(tool=custom_tool) + prompts: list[ + ToolStudioPrompt + ] = PromptStudioHelper.fetch_prompt_from_tool( + tool_id=custom_tool.tool_id + ) + metadata = PromptStudioRegistryHelper.frame_export_json( + tool=custom_tool, prompts=prompts + ) + + obj: PromptStudioRegistry + created: bool + obj, created = PromptStudioRegistry.objects.update_or_create( + custom_tool=custom_tool, + defaults={ + "name": custom_tool.tool_name, + "tool_property": properties.to_dict(), + "tool_spec": spec.to_dict(), + "tool_metadata": metadata, + "icon": custom_tool.icon, + "description": custom_tool.description, + }, + ) + if created: + logger.info(f"PSR {obj.prompt_registry_id} was created") + else: + logger.info(f"PSR {obj.prompt_registry_id} was updated") + return obj + except IntegrityError as error: + logger.error( + "Integrity Error - Error occurred while " + f"exporting custom tool : {error}" + ) + raise ToolSaveError + + @staticmethod + def frame_export_json( + tool: CustomTool, prompts: list[ToolStudioPrompt] + ) -> dict[str, Any]: + export_metadata = {} + + prompt_grammer = tool.prompt_grammer + grammar_list = [] + grammer_dict = {} + outputs: list[dict[str, Any]] = [] + output: dict[str, Any] = {} + if prompt_grammer: + for word, synonyms in prompt_grammer.items(): + synonyms = prompt_grammer[word] + grammer_dict[JsonSchemaKey.WORD] = word + grammer_dict[JsonSchemaKey.SYNONYMS] = synonyms + grammar_list.append(grammer_dict) + grammer_dict = {} + + export_metadata[JsonSchemaKey.NAME] = tool.tool_name + export_metadata[JsonSchemaKey.DESCRIPTION] = tool.description + export_metadata[JsonSchemaKey.AUTHOR] = tool.author + export_metadata[JsonSchemaKey.TOOL_ID] = str(tool.tool_id) + + vector_db = "" + embedding_suffix = "" + adapter_id = "" + llm = "" + embedding_model = "" + + for prompt in prompts: + if not tool.default_profile: + raise ProfileErrors() + if not prompt.profile_manager: + prompt.profile_manager = tool.default_profile + + vector_db = str(prompt.profile_manager.vector_store.id) + embedding_model = str(prompt.profile_manager.embedding_model.id) + llm = str(prompt.profile_manager.llm.id) + x2text = str(prompt.profile_manager.x2text.id) + adapter_id = str(prompt.profile_manager.embedding_model.adapter_id) + embedding_suffix = adapter_id.split("|")[0] + + output[ + JsonSchemaKey.ASSERTION_FAILURE_PROMPT + ] = prompt.assertion_failure_prompt + output[JsonSchemaKey.ASSERT_PROMPT] = prompt.assert_prompt + output[JsonSchemaKey.IS_ASSERT] = prompt.is_assert + output[JsonSchemaKey.PROMPT] = prompt.prompt + output[JsonSchemaKey.ACTIVE] = prompt.active + output[JsonSchemaKey.CHUNK_SIZE] = prompt.profile_manager.chunk_size + output[JsonSchemaKey.VECTOR_DB] = vector_db + output[JsonSchemaKey.EMBEDDING] = embedding_model + output[JsonSchemaKey.X2TEXT_ADAPTER] = x2text + output[ + JsonSchemaKey.CHUNK_OVERLAP + ] = prompt.profile_manager.chunk_overlap + output[JsonSchemaKey.LLM] = llm + output[JsonSchemaKey.PREAMBLE] = tool.preamble + output[JsonSchemaKey.POSTAMBLE] = tool.postamble + output[JsonSchemaKey.GRAMMAR] = grammar_list + output[JsonSchemaKey.TYPE] = prompt.enforce_type + output[JsonSchemaKey.NAME] = prompt.prompt_key + output[ + JsonSchemaKey.RETRIEVAL_STRATEGY + ] = prompt.profile_manager.retrieval_strategy + output[ + JsonSchemaKey.SIMILARITY_TOP_K + ] = prompt.profile_manager.similarity_top_k + output[JsonSchemaKey.SECTION] = prompt.profile_manager.section + output[JsonSchemaKey.REINDEX] = prompt.profile_manager.reindex + output[JsonSchemaKey.EMBEDDING_SUFFIX] = embedding_suffix + outputs.append(output) + output = {} + vector_db = "" + embedding_suffix = "" + adapter_id = "" + llm = "" + embedding_model = "" + + export_metadata[JsonSchemaKey.OUTPUTS] = outputs + return export_metadata + + @staticmethod + def fetch_json_for_registry() -> list[dict[str, Any]]: + try: + prompt_studio_tools = PromptStudioRegistry.objects.all() + pi_serializer = PromptStudioRegistrySerializer( + instance=prompt_studio_tools, many=True + ) + except Exception as error: + logger.error( + f"Error occured while fetching tool for tool_id: {error}" + ) + raise InternalError() + tool_metadata: dict[str, Any] = {} + tool_list = [] + for prompts in pi_serializer.data: + tool_metadata[JsonSchemaKey.NAME] = prompts.get(JsonSchemaKey.NAME) + tool_metadata[JsonSchemaKey.DESCRIPTION] = prompts.get( + JsonSchemaKey.DESCRIPTION + ) + tool_metadata[JsonSchemaKey.ICON] = prompts.get(JsonSchemaKey.ICON) + tool_metadata[JsonSchemaKey.FUNCTION_NAME] = prompts.get( + JsonSchemaKey.PROMPT_REGISTRY_ID + ) + tool_list.append(tool_metadata) + tool_metadata = {} + return tool_list diff --git a/backend/prompt_studio/prompt_studio_registry/serializers.py b/backend/prompt_studio/prompt_studio_registry/serializers.py new file mode 100644 index 000000000..690a10fbc --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/serializers.py @@ -0,0 +1,14 @@ +from backend.serializers import AuditSerializer +from rest_framework import serializers + +from .models import PromptStudioRegistry + + +class PromptStudioRegistrySerializer(AuditSerializer): + class Meta: + model = PromptStudioRegistry + fields = "__all__" + + +class ExportToolRequestSerializer(serializers.Serializer): + prompt_registry_id = serializers.UUIDField(required=True) diff --git a/backend/prompt_studio/prompt_studio_registry/static/select_choices.json b/backend/prompt_studio/prompt_studio_registry/static/select_choices.json new file mode 100644 index 000000000..e2217bef7 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/static/select_choices.json @@ -0,0 +1,31 @@ +{ + "combined_output": + { + "JSON":"JSON", + "YAML":"YAML" + }, + "choose_llm":{ + "AZURE":"Azure OpenAI" + }, + "output_type":{ + "string":"Text", + "float":"Number", + "int":"Integer" + }, + "output_processing":{ + "DEFAULT":"Default" + }, + "embedding":{ + "azure_openai_embedding":"azure_openai_embedding", + "openai_embedding":"openai_embedding" + }, + "retrieval_strategy":{ + "simple":"simple", + "subquestion":"subquestion", + "vector_keyword":"vector_keyword" + }, + "vector_store":{ + "Postgres pg_vector":"Postgres pg_vector", + "qdrant":"qdrant" + } +} diff --git a/backend/prompt_studio/prompt_studio_registry/urls.py b/backend/prompt_studio/prompt_studio_registry/urls.py new file mode 100644 index 000000000..68aed0856 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/urls.py @@ -0,0 +1,15 @@ +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns + +from .views import PromptStudioRegistryView + +tool_studio_export = PromptStudioRegistryView.as_view({"get": "export_tool"}) +urlpatterns = format_suffix_patterns( + [ + path( + "export/", + tool_studio_export, + name="prompt_studio_export", + ), + ] +) diff --git a/backend/prompt_studio/prompt_studio_registry/views.py b/backend/prompt_studio/prompt_studio_registry/views.py new file mode 100644 index 000000000..330721b81 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_registry/views.py @@ -0,0 +1,71 @@ +import logging +from typing import Optional + +from django.db.models import QuerySet +from prompt_studio.prompt_studio_core.models import CustomTool +from prompt_studio.prompt_studio_registry.constants import ( + PromptStudioRegistryKeys, +) +from prompt_studio.prompt_studio_registry.exceptions import ToolDoesNotExist +from prompt_studio.prompt_studio_registry.prompt_studio_registry_helper import ( + PromptStudioRegistryHelper, +) +from prompt_studio.prompt_studio_registry.serializers import ( + ExportToolRequestSerializer, + PromptStudioRegistrySerializer, +) +from rest_framework import status, viewsets +from rest_framework.decorators import action +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning +from utils.filtering import FilterHelper + +from .models import PromptStudioRegistry + +logger = logging.getLogger(__name__) + + +class PromptStudioRegistryView(viewsets.ModelViewSet): + """Driver class to handle export and registering of custom tools to private + tool hub.""" + + versioning_class = URLPathVersioning + queryset = PromptStudioRegistry.objects.all() + serializer_class = PromptStudioRegistrySerializer + + def get_queryset(self) -> Optional[QuerySet]: + filterArgs = FilterHelper.build_filter_args( + self.request, + PromptStudioRegistryKeys.PROMPT_REGISTRY_ID, + ) + if filterArgs: + queryset = PromptStudioRegistry.objects.filter(**filterArgs) + else: + queryset = PromptStudioRegistry.objects.all() + return queryset + + @action(detail=True, methods=["get"]) + def export_tool(self, request: Request) -> Response: + """API Endpoint for exporting required jsons for the custom tool.""" + serializer = ExportToolRequestSerializer(data=request.query_params) + serializer.is_valid(raise_exception=True) + + custom_tool_id = serializer.validated_data.get( + PromptStudioRegistryKeys.PROMPT_REGISTRY_ID + ) + try: + custom_tool = CustomTool.objects.get(tool_id=custom_tool_id) + except CustomTool.DoesNotExist as error: + logger.error( + f"Error occured while fetching tool \ + for tool_id:{custom_tool_id} {error}" + ) + raise ToolDoesNotExist from error + PromptStudioRegistryHelper.update_or_create_psr_tool( + custom_tool=custom_tool + ) + return Response( + {"message": "Custom tool exported sucessfully."}, + status=status.HTTP_200_OK, + ) diff --git a/backend/pyproject.toml b/backend/pyproject.toml new file mode 100644 index 000000000..774d9d5da --- /dev/null +++ b/backend/pyproject.toml @@ -0,0 +1,88 @@ +[build-system] +requires = ["pdm-backend"] +build-backend = "pdm.backend" + +[project] +name = "unstract-backend" +version = "0.0.1" +description = "Unstract backend built with Django to build and schedule ETL pipelines around unstructured data." +authors = [ + {name = "Zipstack Inc.", email = "devsupport@zipstack.com"} +] +dependencies = [ + "Authlib==1.2.1", # For Auth plugins + "boto3~=1.28.17", # For Unstract-cloud-storage + "celery>=5.3.4", # For Celery + "flower>=2.0.1", # Celery Monitoring + "cron-descriptor==1.4.0", # For cron string description + "cryptography>=41.0.7", + "django==4.2.1", + "djangorestframework==3.14.0", + "django-cors-headers==4.3.1", + "django-celery-beat>=2.5.0", + "django-redis==5.4.0", + "django-tenants==3.5.0", + "drf-standardized-errors>=0.12.6", + "drf-yasg==1.21.7", # For API docs + "psycopg2-binary==2.9.9", + "python-dotenv==1.0.0", + "python-magic==0.4.27", # For file upload/download + "python-socketio==5.9.0", # For log_events + "social-auth-app-django==5.3.0", # For OAuth + "social-auth-core==4.4.2", # For OAuth + "unstract-sdk~=0.11.1", + "unstract-adapters~=0.2.1", + # ! IMPORTANT! + # Indirect local dependencies usually need to be added in their own projects + # as: https://pdm-project.org/latest/usage/dependency/#local-dependencies. + # + # However, such indirect local dependencies which are not direct depedency of + # main project appear as absolute paths in pdm.lock of main project, making it + # impossible to check in the lock file. + # + # Hence required to add all indirect local dependencies too here. + "unstract-connectors @ file:///${PROJECT_ROOT}/../unstract/connectors", + "unstract-core @ file:///${PROJECT_ROOT}/../unstract/core", + "unstract-flags @ file:///${PROJECT_ROOT}/../unstract/flags", + "unstract-tool-registry @ file:///${PROJECT_ROOT}/../unstract/tool-registry", + "unstract-tool-sandbox @ file:///${PROJECT_ROOT}/../unstract/tool-sandbox", + "unstract-workflow-execution @ file:///${PROJECT_ROOT}/../unstract/workflow-execution", +] +# <3.11.1 due to resolution error from Unstract SDK +requires-python = ">=3.9,<3.11.1" +readme = "README.md" +classifiers = [ + "Private :: Do Not Upload", + "Framework :: Django", + "Programming Language :: Python" +] + +[tool.pdm.dev-dependencies] +deploy = [ + "gunicorn>=21.2.0", +] +test = [ + "pytest>=8.0.1", +] + +[tool.pdm.scripts] +# Commands for backend +backend.cmd = "./entrypoint.sh" +backend.env_file = ".env" +backend.help = "Runs the Unstract backend" +# Commands for backend db migration +migrate_db.cmd = "python manage.py migrate" +migrate_db.env_file = ".env" +migrate_db.help = "Performs DB migrations for Unstract backend" +# Commands for backend execution +consumer.cmd = "celery -A backend worker --loglevel=info" +consumer.env_file = ".env" +consumer.help = "Runs the Unstract consumer" +# Celery Flower +flower.cmd = "celery -A backend flower --port=5555" +flower.env_file = ".env" +flower.help = "Runs the Unstract Celery Monitoring Tool" +# Celery Beat +beat.cmd = "celery -A backend beat --loglevel=info" +beat.env_file = ".env" +beat.help = "Runs the Unstract Celery Beat service" diff --git a/backend/sample.env b/backend/sample.env new file mode 100644 index 000000000..20c96f0fd --- /dev/null +++ b/backend/sample.env @@ -0,0 +1,102 @@ +DJANGO_SETTINGS_MODULE='backend.settings.dev' + +# Common +PATH_PREFIX="api/v1" + +# Django settings +DJANGO_APP_BACKEND_URL=http://frontend.unstract.localhost +DJANGO_SECRET_KEY="1(xf&nc6!y7!l&!5xe&i_rx7e^m@fcut9fduv86ft=-b@2g6" + +# Postgres DB envs +DB_HOST='unstract-db' +DB_USER='unstract_dev' +DB_PASSWORD='unstract_pass' +DB_NAME='unstract_db' +DB_PORT=5432 + +# Redis +REDIS_HOST="unstract-redis" +REDIS_PORT=6379 +REDIS_PASSWORD="" +REDIS_USER=default + +# Connector OAuth +SOCIAL_AUTH_EXTRA_DATA_EXPIRATION_TIME_IN_SECOND=3600 +GOOGLE_OAUTH2_KEY= +GOOGLE_OAUTH2_SECRET= + +# User session +SESSION_EXPIRATION_TIME_IN_SECOND= + +# FE Web Application Dependencies +LOGIN_NEXT_URL="http://frontend.unstract.localhost/org" +LANDING_URL="http://frontend.unstract.localhost/landing" +ERROR_URL="http://frontend.unstract.localhost/error" +WEB_APP_ORIGIN_URL="http://frontend.unstract.localhost" + +# Azure OpenAI +OPENAI_API_KEY= +OPENAI_API_BASE= +OPENAI_API_VERSION= +OPENAI_API_ENGINE= +OPENAI_API_MODEL= +OPENAI_API_MODEL_EMBEDDING= +OPENAI_API_DEPLOYMENT_EMBEDDING= +OPENAI_API_TYPE= + +# API keys for trusted services +INTERNAL_SERVICE_API_KEY= + +# Unstract Core envs +BUILTIN_FUNCTIONS_API_KEY= + +FREE_STORAGE_AWS_ACCESS_KEY_ID= +FREE_STORAGE_AWS_SECRET_ACCESS_KEY= +UNSTRACT_FREE_STORAGE_BUCKET_NAME= + +GOOGLE_SERVICE_ACCOUNT= +GOOGLE_PROJECT_ID= +GOOGLE_STORAGE_ACCESS_KEY_ID= +GOOGLE_STORAGE_SECRET_ACCESS_KEY= +GOOGLE_STORAGE_BASE_URL=https://storage.googleapis.com + +# API storage +API_STORAGE_DIR = "/data/api" + +# Platform Service +PLATFORM_SERVICE_HOST=http://unstract-platform-service +PLATFORM_SERVICE_PORT=3001 + +# Worker Service +UNSTRACT_WORKER_HOST=http://unstract-worker +UNSTRACT_WORKER_PORT=5002 + +# Document Service +DOCUMENT_PROCESSOR_URL=http://unstract-document-service:3002 +DOCUMENT_PROCESSOR_API_KEY= + +# Workflow execution +WORKFLOW_DATA_DIR = "/data/execution" + +# Prompt Service +PROMPT_HOST=http://unstract-prompt-service +PROMPT_PORT=3003 + +#Prompt Studio +PROMPT_STUDIO_FILE_PATH=/app/prompt-studio-data + +# Structure Tool +STRUCTURE_TOOL_IMAGE_URL="docker:unstract/tool-structure:0.0.1" +STRUCTURE_TOOL_IMAGE_NAME="unstract/tool-structure" +STRUCTURE_TOOL_IMAGE_TAG="0.0.1" + +# Feature Flags +EVALUATION_SERVER_IP=localhost +EVALUATION_SERVER_PORT=9005 +# Stubs generator +PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python + + +#X2Text Service +X2TEXT_HOST=http://unstract-x2text-service +X2TEXT_PORT=3004 diff --git a/backend/scheduler/__init__.py b/backend/scheduler/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/scheduler/admin.py b/backend/scheduler/admin.py new file mode 100644 index 000000000..846f6b406 --- /dev/null +++ b/backend/scheduler/admin.py @@ -0,0 +1 @@ +# Register your models here. diff --git a/backend/scheduler/apps.py b/backend/scheduler/apps.py new file mode 100644 index 000000000..e324a1f85 --- /dev/null +++ b/backend/scheduler/apps.py @@ -0,0 +1,14 @@ +import logging + +from django.apps import AppConfig + +logger = logging.getLogger(__name__) + + +class SchedulerConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "scheduler" + + def ready(self) -> None: + super().ready() + return diff --git a/backend/scheduler/constants.py b/backend/scheduler/constants.py new file mode 100644 index 000000000..30067f8c9 --- /dev/null +++ b/backend/scheduler/constants.py @@ -0,0 +1,12 @@ +class SchedulerConstants: + """Constants used by the scheduler app.""" + + # Adding a cron job + ID = "id" + NAME = "name" + JOB_KWARGS = "job_kwargs" + SCHEDULER_KWARGS = "scheduler_kwargs" + + # Default strings + DEFAULT_CRON_STRING = "0 9 * * 1" + JOB_ID_REPLACE_TAG = "" diff --git a/backend/scheduler/exceptions.py b/backend/scheduler/exceptions.py new file mode 100644 index 000000000..4fcc131e9 --- /dev/null +++ b/backend/scheduler/exceptions.py @@ -0,0 +1,11 @@ +from rest_framework.exceptions import APIException + + +class JobSchedulingError(APIException): + status_code = 500 + default_detail = "Error occured while scheduling the job" + + +class JobDeletionError(APIException): + status_code = 404 + default_detail = "Error occured while deleting the job" diff --git a/backend/scheduler/helper.py b/backend/scheduler/helper.py new file mode 100644 index 000000000..3a83b1eb3 --- /dev/null +++ b/backend/scheduler/helper.py @@ -0,0 +1,53 @@ +import logging + +from cron_expression_generator.constants import CronKeys +from django.core.exceptions import ValidationError +from scheduler import views +from scheduler.constants import SchedulerConstants as SC +from scheduler.exceptions import JobDeletionError, JobSchedulingError +from scheduler.serializer import AddJobSerializer +from scheduler.tasks import delete_periodic_task + +logger = logging.getLogger(__name__) + +class SchedulerHelper: + @staticmethod + def add_job( + pipeline_id: str, cron_string: str = SC.DEFAULT_CRON_STRING + ) -> None: + logger.info(f"Scheduling job for {pipeline_id} with {cron_string}") + name = f"Pipeline job-{pipeline_id}" + job_serialize_data = { + SC.ID: pipeline_id, + CronKeys.CRON_STRING: cron_string, + SC.NAME: name, + } + try: + job_serializer = AddJobSerializer(data=job_serialize_data) + job_serializer.is_valid(raise_exception=True) + except ValidationError as e: + logger.error(f"Validation error while scheduling job: {e}") + raise JobSchedulingError + except Exception as e: + logger.error(f"Unhandled exception while scheduling job: {e}") + raise JobSchedulingError + + try: + # Celery based scheduler + scheduler_response = views.schedule_task_job( + pipeline_id, job_serializer.validated_data + ) + logger.info(f"Scheduler response: {scheduler_response}") + except Exception as e: + logger.error(f"Exception while adding job: {e}") + raise JobSchedulingError + + @staticmethod + def remove_job(pipeline_id: str) -> None: + logger.info(f"Removing job for {pipeline_id}") + try: + logger.info("Celery scheduler - removing job") + delete_periodic_task(pipeline_id) + except Exception as e: + logger.error(f"Exception while removing job: {e}") + raise JobDeletionError diff --git a/backend/scheduler/serializer.py b/backend/scheduler/serializer.py new file mode 100644 index 000000000..feadb34bd --- /dev/null +++ b/backend/scheduler/serializer.py @@ -0,0 +1,50 @@ +import logging +from typing import Any + +from backend.constants import FieldLengthConstants as FieldLength +from django.conf import settings +from pipeline.manager import PipelineManager +from rest_framework import serializers +from scheduler.constants import SchedulerConstants as SC + +logger = logging.getLogger(__name__) + +JOB_NAME_LENGTH = 255 + + +class JobKwargsSerializer(serializers.Serializer): + verb = serializers.CharField(max_length=6) + # TODO: Add custom URL field to allow URLs for running in docker + # url = serializers.URLField() + url = serializers.CharField(max_length=128) + headers = serializers.JSONField() + params = serializers.JSONField() + data = serializers.JSONField() + + +class SchedulerKwargsSerializer(serializers.Serializer): + coalesce = serializers.BooleanField() + misfire_grace_time = serializers.IntegerField(allow_null=True, required=False) + max_instances = serializers.IntegerField() + replace_existing = serializers.BooleanField() + + +class AddJobSerializer(serializers.Serializer): + id = serializers.CharField(max_length=FieldLength.UUID_LENGTH) + cron_string = serializers.CharField(max_length=FieldLength.CRON_LENGTH) + name = serializers.CharField( + max_length=JOB_NAME_LENGTH, required=False, allow_blank=True + ) + job_kwargs = JobKwargsSerializer(write_only=True) + scheduler_kwargs = SchedulerKwargsSerializer(write_only=True) + + def to_internal_value(self, data: dict[str, Any]) -> dict[str, Any]: + if SC.NAME not in data: + data[SC.NAME] = f"Job-{data[SC.ID]}" + data[ + SC.JOB_KWARGS + ] = PipelineManager.get_pipeline_execution_data_for_scheduled_run( + pipeline_id=data[SC.ID] + ) + data[SC.SCHEDULER_KWARGS] = settings.SCHEDULER_KWARGS + return super().to_internal_value(data) # type: ignore diff --git a/backend/scheduler/settings.py b/backend/scheduler/settings.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/scheduler/tasks.py b/backend/scheduler/tasks.py new file mode 100644 index 000000000..f686fb77f --- /dev/null +++ b/backend/scheduler/tasks.py @@ -0,0 +1,122 @@ +import json +import logging +from typing import Any, Optional + +from pipeline.models import Pipeline +from account.models import Organization +from celery import shared_task +from django_celery_beat.models import CrontabSchedule, PeriodicTask +from django_tenants.utils import get_tenant_model, tenant_context +from pymysql import IntegrityError +from workflow_manager.workflow.models.workflow import Workflow +from workflow_manager.workflow.workflow_helper import WorkflowHelper +from pipeline.pipeline_processor import PipelineProcessor + +logger = logging.getLogger(__name__) + + +def create_periodic_task( + cron_string: str, + task_name: str, + task_path: str, + task_args: list[Any], +) -> None: + try: + # Convert task_args to JSON + task_args_json = json.dumps(task_args) + except TypeError as te: + logger.error(f"Failed : task_args is not JSON serializable: {te}") + return + + # Parse the cron string + minute, hour, day_of_month, month_of_year, day_of_week = cron_string.split() + + # Create a crontab schedule + schedule, _ = CrontabSchedule.objects.get_or_create( + minute=minute, + hour=hour, + day_of_week=day_of_week, + day_of_month=day_of_month, + month_of_year=month_of_year, + ) + + logger.info(f"Creating periodic task with cron string: {cron_string}") + + # Create periodic task + try: + logger.info(f"Running periodic task addition to beat table: {schedule}") + PeriodicTask.objects.create( + crontab=schedule, + name=task_name, + task=task_path, + args=task_args_json, + ) + logger.info( + f"Completed running task addition to beat table: {task_name}" + ) + except Exception as e: + logger.error(f"Failed to create periodic task: {e}") + + +def update_pipeline( + pipeline_guid: Optional[str], status: tuple[str, str] +) -> Any: + if pipeline_guid: + pipeline: Pipeline = PipelineProcessor.fetch_pipeline( + pipeline_id=pipeline_guid + ) + PipelineProcessor.update_pipeline_status( + pipeline=pipeline, is_end=True, status=status + ) + logger.info(f"Updated pipeline status: {status}") + + +@shared_task +def execute_pipeline_task( + workflow_id: Any, + org_schema: Any, + execution_action: Any, + execution_id: Any, + pipepline_id: Any, + with_logs: Any, + name: Any, +) -> None: + logger.info(f"Executing pipeline name: {name}") + + try: + logger.info(f"Executing workflow id: {workflow_id}") + tenant: Organization = ( + get_tenant_model().objects.filter(schema_name=org_schema).first() + ) + with tenant_context(tenant): + workflow = Workflow.objects.get(id=workflow_id) + try: + logger.info(f"Executing workflow: {workflow}") + update_pipeline( + pipepline_id, Pipeline.PipelineStatus.INPROGRESS + ) + execution_response = WorkflowHelper.complete_execution( + workflow, execution_id, pipepline_id, with_logs + ) + logger.info(f"Execution response: {execution_response}") + update_pipeline(pipepline_id, Pipeline.PipelineStatus.SUCCESS) + except IntegrityError: + logger.error( + f"Failed to complete execution for workflow: {workflow}" + ) + update_pipeline(pipepline_id, Pipeline.PipelineStatus.FAILURE) + logger.info(f"Execution completed for pipeline: {name}") + except Exception as e: + logger.error(f"Failed to execute pipeline: {name}. Error: {e}") + + +def delete_periodic_task(task_name: str) -> None: + try: + task = PeriodicTask.objects.get(name=task_name) + task.delete() + + logger.info(f"Deleted periodic task: {task_name}") + except PeriodicTask.DoesNotExist: + logger.error(f"Periodic task does not exist: {task_name}") + except Exception as e: + logger.error(f"Failed to delete periodic task: {e}") diff --git a/backend/scheduler/views.py b/backend/scheduler/views.py new file mode 100644 index 000000000..e772b26d8 --- /dev/null +++ b/backend/scheduler/views.py @@ -0,0 +1,86 @@ +import logging +import uuid +from typing import Any + +from django.db import connection +from pipeline.models import Pipeline +from pipeline.pipeline_processor import PipelineProcessor +from rest_framework.response import Response +from scheduler.tasks import create_periodic_task +from workflow_manager.workflow.constants import ( + WorkflowExecutionKey, + WorkflowKey, +) +from workflow_manager.workflow.exceptions import ( + WorkflowExecutionBadRequestException, +) +from workflow_manager.workflow.serializers import ExecuteWorkflowSerializer +from workflow_manager.workflow.views import WorkflowViewSet + +logger = logging.getLogger(__name__) + + +def schedule_task_job(pipeline_id: str, job_data: Any) -> Response: + try: + # Validating request + if "cron_string" not in job_data: + return Response({"error": "cron_string is required"}, status=400) + if "id" not in job_data: + return Response({"error": "id is required"}, status=400) + if "job_kwargs" in job_data and not isinstance( + job_data["job_kwargs"], dict + ): + return Response( + {"error": "job_kwargs is required to be a dict"}, status=400 + ) + + cron_string = job_data.get("cron_string") + name = job_data.get("name") + job_kwargs = job_data.get("job_kwargs", {}) + task_data = job_kwargs.get("data", {}) + params = job_kwargs.get("params", {}) + with_logs = params.get("with_logs", False) + + pipeline: Pipeline = PipelineProcessor.initialize_pipeline_sync( + pipeline_id + ) + + task_data[WorkflowKey.WF_ID] = pipeline.workflow.id + execution_id = str(uuid.uuid4()) + task_data[WorkflowExecutionKey.EXECUTION_ID] = execution_id + workflow_viewset = WorkflowViewSet() + workflow_viewset.serializer_class = ExecuteWorkflowSerializer + serializer = ExecuteWorkflowSerializer(data=task_data) + + if not serializer.is_valid(): + raise WorkflowExecutionBadRequestException( + workflow_viewset.get_error_from_serializer(serializer.errors) + ) + + workflow_id = serializer.get_workflow_id(serializer.validated_data) + + execution_action = serializer.get_execution_action( + serializer.validated_data + ) + org_schema = connection.tenant.schema_name + + create_periodic_task( + cron_string=cron_string, + task_name=pipeline.pk, + task_path="scheduler.tasks.execute_pipeline_task", + task_args=[ + str(workflow_id), + org_schema, + execution_action or "", + execution_id, + str(pipeline.pk), + bool(with_logs), + str(name), + ], + ) + + return Response({"message": "Job scheduled successfully"}, status=200) + + except Exception as e: + logger.error(f"Exception while scheduling job: {e}") + return Response({"error": str(e)}, status=500) diff --git a/backend/tenant_account/__init__.py b/backend/tenant_account/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/tenant_account/admin.py b/backend/tenant_account/admin.py new file mode 100644 index 000000000..846f6b406 --- /dev/null +++ b/backend/tenant_account/admin.py @@ -0,0 +1 @@ +# Register your models here. diff --git a/backend/tenant_account/apps.py b/backend/tenant_account/apps.py new file mode 100644 index 000000000..8549865f7 --- /dev/null +++ b/backend/tenant_account/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class TenantAccountConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "tenant_account" diff --git a/backend/tenant_account/constants.py b/backend/tenant_account/constants.py new file mode 100644 index 000000000..29ba63684 --- /dev/null +++ b/backend/tenant_account/constants.py @@ -0,0 +1,14 @@ +class PlatformServiceConstants: + IS_ACTIVE = "is_active" + KEY = "key" + ORGANIZATION = "organization" + ID = "id" + ACTIVATE = "ACTIVATE" + DEACTIVATE = "DEACTIVATE" + ACTION = "action" + KEY_NAME = "key_name" + + +class ErrorMessage: + KEY_EXIST = "Key name already exists" + DUPLICATE_API = "It appears that a duplicate call may have been made." diff --git a/backend/tenant_account/dto.py b/backend/tenant_account/dto.py new file mode 100644 index 000000000..16c37ea58 --- /dev/null +++ b/backend/tenant_account/dto.py @@ -0,0 +1,15 @@ +from dataclasses import dataclass + + +@dataclass +class OrganizationLoginResponse: + name: str + display_name: str + organization_id: str + created_at: str + + +@dataclass +class ResetUserPasswordDto: + status: bool + message: str diff --git a/backend/tenant_account/enums.py b/backend/tenant_account/enums.py new file mode 100644 index 000000000..d8209ec2d --- /dev/null +++ b/backend/tenant_account/enums.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class UserRole(Enum): + USER = "user" + ADMIN = "admin" diff --git a/backend/tenant_account/invitation_urls.py b/backend/tenant_account/invitation_urls.py new file mode 100644 index 000000000..2176aaa6f --- /dev/null +++ b/backend/tenant_account/invitation_urls.py @@ -0,0 +1,20 @@ +from django.urls import path +from tenant_account.invitation_views import InvitationViewSet + +invitation_list = InvitationViewSet.as_view( + { + "get": InvitationViewSet.list_invitations.__name__, + } +) + +invitation_details = InvitationViewSet.as_view( + { + "delete": InvitationViewSet.delete_invitation.__name__, + } +) + + +urlpatterns = [ + path("", invitation_list, name="invitation_list"), + path("/", invitation_details, name="invitation_details"), +] diff --git a/backend/tenant_account/invitation_views.py b/backend/tenant_account/invitation_views.py new file mode 100644 index 000000000..8d727eb74 --- /dev/null +++ b/backend/tenant_account/invitation_views.py @@ -0,0 +1,44 @@ +import logging + +from account.authentication_controller import AuthenticationController +from account.dto import MemberInvitation +from rest_framework import status, viewsets +from rest_framework.decorators import action +from rest_framework.request import Request +from rest_framework.response import Response +from tenant_account.serializer import ListInvitationsResponseSerializer + +Logger = logging.getLogger(__name__) + + +class InvitationViewSet(viewsets.ViewSet): + @action(detail=False, methods=["GET"]) + def list_invitations(self, request: Request) -> Response: + auth_controller = AuthenticationController() + invitations: list[MemberInvitation] = auth_controller.get_user_invitations( + organization_id=request.org_id, + ) + serialized_members = ListInvitationsResponseSerializer( + invitations, many=True + ).data + return Response( + status=status.HTTP_200_OK, + data={"message": "success", "members": serialized_members}, + ) + + @action(detail=False, methods=["DELETE"]) + def delete_invitation(self, request: Request, id: str) -> Response: + auth_controller = AuthenticationController() + is_deleted: bool = auth_controller.delete_user_invitation( + organization_id=request.org_id, invitation_id=id + ) + if is_deleted: + return Response( + status=status.HTTP_204_NO_CONTENT, + data={"status": "success", "message": "success"}, + ) + else: + return Response( + status=status.HTTP_404_NOT_FOUND, + data={"status": "failed", "message": "failed"}, + ) diff --git a/backend/tenant_account/migrations/0001_initial.py b/backend/tenant_account/migrations/0001_initial.py new file mode 100644 index 000000000..cad92899c --- /dev/null +++ b/backend/tenant_account/migrations/0001_initial.py @@ -0,0 +1,42 @@ +# Generated by Django 4.2.1 on 2023-07-18 15:34 + +import django.contrib.auth.models +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + ("account", "0002_auto_20230718_1040"), + ] + + operations = [ + migrations.CreateModel( + name="User", + fields=[ + ( + "user_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "verbose_name": "user", + "verbose_name_plural": "users", + "abstract": False, + }, + bases=("account.user",), + managers=[ + ("objects", django.contrib.auth.models.UserManager()), + ], + ), + ] diff --git a/backend/tenant_account/migrations/0002_organizationmember_delete_user.py b/backend/tenant_account/migrations/0002_organizationmember_delete_user.py new file mode 100644 index 000000000..6a41c4aa8 --- /dev/null +++ b/backend/tenant_account/migrations/0002_organizationmember_delete_user.py @@ -0,0 +1,45 @@ +# Generated by Django 4.2.1 on 2023-08-21 11:12 + +import django.contrib.auth.models +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("account", "0002_auto_20230718_1040"), + ("tenant_account", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="OrganizationMember", + fields=[ + ( + "user_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to=settings.AUTH_USER_MODEL, + ), + ), + ("role", models.CharField(default="admin")), + ], + options={ + "verbose_name": "user", + "verbose_name_plural": "users", + "abstract": False, + }, + bases=("account.user",), + managers=[ + ("objects", django.contrib.auth.models.UserManager()), + ], + ), + migrations.DeleteModel( + name="User", + ), + ] diff --git a/backend/tenant_account/migrations/0003_alter_organizationmember_options_and_more.py b/backend/tenant_account/migrations/0003_alter_organizationmember_options_and_more.py new file mode 100644 index 000000000..3a16c85e9 --- /dev/null +++ b/backend/tenant_account/migrations/0003_alter_organizationmember_options_and_more.py @@ -0,0 +1,55 @@ +# Generated by Django 4.2.1 on 2023-09-15 12:11 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("tenant_account", "0002_organizationmember_delete_user"), + ] + + operations = [ + migrations.AlterModelOptions( + name="organizationmember", + options={}, + ), + migrations.AlterModelManagers( + name="organizationmember", + managers=[], + ), + migrations.RenameField( + model_name="organizationmember", + old_name="user_ptr", + new_name="user", + ), + migrations.AlterField( + model_name="organizationmember", + name="user", + field=models.OneToOneField( + default=None, + on_delete=django.db.models.deletion.CASCADE, + related_name="organization_member", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="organizationmember", + name="member_id", + field=models.BigAutoField( + auto_created=True, + default=None, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + preserve_default=False, + ), + migrations.AlterField( + model_name="organizationmember", + name="role", + field=models.CharField(), + ), + ] diff --git a/backend/tenant_account/migrations/0004_alter_organizationmember_member_id.py b/backend/tenant_account/migrations/0004_alter_organizationmember_member_id.py new file mode 100644 index 000000000..9392131db --- /dev/null +++ b/backend/tenant_account/migrations/0004_alter_organizationmember_member_id.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.1 on 2023-09-20 12:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("tenant_account", "0003_alter_organizationmember_options_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="organizationmember", + name="member_id", + field=models.BigAutoField(primary_key=True, serialize=False), + ), + ] diff --git a/backend/tenant_account/migrations/__init__.py b/backend/tenant_account/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/tenant_account/models.py b/backend/tenant_account/models.py new file mode 100644 index 000000000..f4b5b797f --- /dev/null +++ b/backend/tenant_account/models.py @@ -0,0 +1,16 @@ +from account.models import User +from django.db import models + + +class OrganizationMember(models.Model): + member_id = models.BigAutoField(primary_key=True) + user = models.OneToOneField( + User, on_delete=models.CASCADE, default=None, related_name="organization_member" + ) + role = models.CharField() + + def __str__(self): # type: ignore + return ( + f"OrganizationMember(" + f"{self.member_id}, role: {self.role}, userId: {self.user.user_id})" + ) diff --git a/backend/tenant_account/organization_member_service.py b/backend/tenant_account/organization_member_service.py new file mode 100644 index 000000000..673952d15 --- /dev/null +++ b/backend/tenant_account/organization_member_service.py @@ -0,0 +1,26 @@ +from typing import Optional + +from tenant_account.models import OrganizationMember + + +class OrganizationMemberService: + def __init__(self) -> None: + pass + + def get_user_by_email(self, email: str) -> Optional[OrganizationMember]: + try: + return OrganizationMember.objects.get(user__email=email) # type: ignore + except OrganizationMember.DoesNotExist: + return None + + def get_user_by_user_id(self, user_id: str) -> Optional[OrganizationMember]: + try: + return OrganizationMember.objects.get(user__user_id=user_id) # type: ignore + except OrganizationMember.DoesNotExist: + return None + + def get_user_by_id(self, id: str) -> Optional[OrganizationMember]: + try: + return OrganizationMember.objects.get(user=id) # type: ignore + except OrganizationMember.DoesNotExist: + return None diff --git a/backend/tenant_account/serializer.py b/backend/tenant_account/serializer.py new file mode 100644 index 000000000..305efa749 --- /dev/null +++ b/backend/tenant_account/serializer.py @@ -0,0 +1,161 @@ +from collections import OrderedDict +from typing import Any, Optional, Union, cast + +from account.constants import Common +from rest_framework import serializers +from rest_framework.exceptions import ValidationError +from tenant_account.models import OrganizationMember + + +class OrganizationCallbackSerializer(serializers.Serializer): + id = serializers.CharField(required=False) + + +class OrganizationLoginResponseSerializer(serializers.Serializer): + name = serializers.CharField() + display_name = serializers.CharField() + organization_id = serializers.CharField() + created_at = serializers.CharField() + + +class UserInviteResponseSerializer(serializers.Serializer): + email = serializers.CharField(required=True) + status = serializers.CharField(required=True) + message = serializers.CharField(required=False) + + +class OrganizationMemberSerializer(serializers.ModelSerializer): + email = serializers.CharField(source="user.email", read_only=True) + id = serializers.CharField(source="user.id", read_only=True) + + class Meta: + model = OrganizationMember + fields = ("id", "email", "role") + + +class LimitedUserEmailListSerializer(serializers.ListSerializer): + def __init__(self, *args: Any, **kwargs: Any) -> None: + self.max_elements: int = kwargs.pop( + "max_elements", Common.MAX_EMAIL_IN_REQUEST + ) + super().__init__(*args, **kwargs) + + def validate(self, data: list[str]) -> Any: + if len(data) > self.max_elements: + raise ValidationError( + f"Exceeded maximum number of elements ({self.max_elements})" + ) + return data + + +class LimitedUserListSerializer(serializers.ListSerializer): + def __init__(self, *args: Any, **kwargs: Any) -> None: + self.max_elements: int = kwargs.pop( + "max_elements", Common.MAX_EMAIL_IN_REQUEST + ) + super().__init__(*args, **kwargs) + + def validate( + self, data: list[dict[str, Union[str, None]]] + ) -> list[dict[str, Union[str, None]]]: + if len(data) > self.max_elements: + raise ValidationError( + f"Exceeded maximum number of elements ({self.max_elements})" + ) + + for item in data: + if not isinstance(item, dict): + raise ValidationError( + "Each item in the list must be a dictionary." + ) + if "email" not in item: + raise ValidationError( + "Each item in the list must have 'email' key." + ) + if "role" not in item: + item["role"] = None + + return data + + +class InviteUserSerializer(serializers.Serializer): + users = LimitedUserListSerializer( + required=True, + child=serializers.DictField( + child=serializers.CharField(max_length=255, required=True), + required=False, # Make 'role' field optional + ), + max_elements=Common.MAX_EMAIL_IN_REQUEST, + ) + + def get_users( + self, validated_data: dict[str, Any] + ) -> list[dict[str, Union[str, None]]]: + return validated_data.get("users", []) + + +class RemoveUserFromOrganizationSerializer(serializers.Serializer): + emails = LimitedUserEmailListSerializer( + required=True, + child=serializers.EmailField(required=True), + max_elements=Common.MAX_EMAIL_IN_REQUEST, + ) + + def get_user_emails( + self, validated_data: dict[str, Union[list[str], None]] + ) -> list[str]: + return cast(list[str], validated_data.get(Common.USER_EMAILS, [])) + + +class ChangeUserRoleRequestSerializer(serializers.Serializer): + email = serializers.EmailField(required=True) + role = serializers.CharField(required=True) + + def get_user_email( + self, validated_data: dict[str, Union[str, None]] + ) -> Optional[str]: + return validated_data.get(Common.USER_EMAIL) + + def get_user_role( + self, validated_data: dict[str, Union[str, None]] + ) -> Optional[str]: + return validated_data.get(Common.USER_ROLE) + + +class DeleteInvitationRequestSerializer(serializers.Serializer): + id = serializers.EmailField(required=True) + + def get_id( + self, validated_data: dict[str, Union[str, None]] + ) -> Optional[str]: + return validated_data.get(Common.ID) + + +class UserInfoSerializer(serializers.Serializer): + id = serializers.CharField() + email = serializers.CharField() + name = serializers.CharField() + display_name = serializers.CharField() + family_name = serializers.CharField() + picture = serializers.CharField() + + +class GetRolesResponseSerializer(serializers.Serializer): + id = serializers.CharField() + name = serializers.CharField() + description = serializers.CharField() + + def to_representation(self, instance: Any) -> OrderedDict[str, Any]: + data: OrderedDict[str, Any] = super().to_representation(instance) + return data + + +class ListInvitationsResponseSerializer(serializers.Serializer): + id = serializers.CharField() + email = serializers.CharField() + created_at = serializers.CharField() + expires_at = serializers.CharField() + + def to_representation(self, instance: Any) -> OrderedDict[str, Any]: + data: OrderedDict[str, Any] = super().to_representation(instance) + return data diff --git a/backend/tenant_account/templates/land.html b/backend/tenant_account/templates/land.html new file mode 100644 index 000000000..8cec6bca6 --- /dev/null +++ b/backend/tenant_account/templates/land.html @@ -0,0 +1,11 @@ + + + + + ZipstackID Django App Example + + +

Welcome Guest

+

dsdasdaddddddddd

+ + diff --git a/backend/tenant_account/tests.py b/backend/tenant_account/tests.py new file mode 100644 index 000000000..a39b155ac --- /dev/null +++ b/backend/tenant_account/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/backend/tenant_account/urls.py b/backend/tenant_account/urls.py new file mode 100644 index 000000000..80146e1d0 --- /dev/null +++ b/backend/tenant_account/urls.py @@ -0,0 +1,11 @@ +from django.urls import include, path +from tenant_account import invitation_urls, users_urls +from tenant_account.views import get_organization, get_roles, reset_password + +urlpatterns = [ + path("roles", get_roles, name="roles"), + path("users/", include(users_urls)), + path("invitation/", include(invitation_urls)), + path("organization", get_organization, name="get_organization"), + path("reset_password", reset_password, name="reset_password"), +] diff --git a/backend/tenant_account/users_urls.py b/backend/tenant_account/users_urls.py new file mode 100644 index 000000000..d087f5e4b --- /dev/null +++ b/backend/tenant_account/users_urls.py @@ -0,0 +1,36 @@ +from django.urls import path +from tenant_account.users_view import OrganizationUserViewSet + +organization_user_role = OrganizationUserViewSet.as_view( + { + "post": OrganizationUserViewSet.assign_organization_role_to_user.__name__, + "delete": OrganizationUserViewSet.remove_organization_role_from_user.__name__, + } +) + +user_profile = OrganizationUserViewSet.as_view( + { + "get": OrganizationUserViewSet.get_user_profile.__name__, + } +) + +invite_user = OrganizationUserViewSet.as_view( + { + "post": OrganizationUserViewSet.invite_user.__name__, + } +) + +organization_users = OrganizationUserViewSet.as_view( + { + "get": OrganizationUserViewSet.get_organization_members.__name__, + "delete": OrganizationUserViewSet.remove_members_from_organization.__name__, + } +) + + +urlpatterns = [ + path("", organization_users, name="organization_user"), + path("profile/", user_profile, name="user_profile"), + path("role/", organization_user_role, name="organization_user_role"), + path("invite/", invite_user, name="invite_user"), +] diff --git a/backend/tenant_account/users_view.py b/backend/tenant_account/users_view.py new file mode 100644 index 000000000..65b7dcfb6 --- /dev/null +++ b/backend/tenant_account/users_view.py @@ -0,0 +1,172 @@ +import logging + +from account.authentication_controller import AuthenticationController +from account.exceptions import BadRequestException +from rest_framework import status, viewsets +from rest_framework.decorators import action +from rest_framework.request import Request +from rest_framework.response import Response +from tenant_account.models import OrganizationMember +from tenant_account.serializer import ( + ChangeUserRoleRequestSerializer, + InviteUserSerializer, + OrganizationMemberSerializer, + RemoveUserFromOrganizationSerializer, + UserInfoSerializer, + UserInviteResponseSerializer, +) + +Logger = logging.getLogger(__name__) + + +class OrganizationUserViewSet(viewsets.ViewSet): + @action(detail=False, methods=["POST"]) + def assign_organization_role_to_user(self, request: Request) -> Response: + serializer = ChangeUserRoleRequestSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + user_email = serializer.get_user_email(serializer.validated_data) + role = serializer.get_user_role(serializer.validated_data) + if not (user_email and role): + raise BadRequestException + org_id: str = request.org_id + auth_controller = AuthenticationController() + + auth_controller = AuthenticationController() + update_status = auth_controller.add_user_role( + request.user, org_id, user_email, role + ) + if update_status: + return Response( + status=status.HTTP_200_OK, + data={"status": "success", "message": "success"}, + ) + else: + return Response( + status=status.HTTP_400_BAD_REQUEST, + data={"status": "failed", "message": "failed"}, + ) + + @action(detail=False, methods=["DELETE"]) + def remove_organization_role_from_user(self, request: Request) -> Response: + serializer = ChangeUserRoleRequestSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + user_email = serializer.get_user_email(serializer.validated_data) + role = serializer.get_user_role(serializer.validated_data) + if not (user_email and role): + raise BadRequestException + org_id: str = request.org_id + auth_controller = AuthenticationController() + + auth_controller = AuthenticationController() + update_status = auth_controller.remove_user_role( + request.user, org_id, user_email, role + ) + if update_status: + return Response( + status=status.HTTP_200_OK, + data={"status": "success", "message": "success"}, + ) + else: + return Response( + status=status.HTTP_400_BAD_REQUEST, + data={"status": "failed", "message": "failed"}, + ) + + @action(detail=False, methods=["GET"]) + def get_user_profile(self, request: Request) -> Response: + auth_controller = AuthenticationController() + try: + # z_code = request.COOKIES.get(Cookie.Z_CODE) + user_info = auth_controller.get_user_info(request) + role = auth_controller.get_organization_members_by_user( + request.user) + if not user_info: + return Response( + status=status.HTTP_404_NOT_FOUND, + data={"message": "User Not Found"}, + ) + serialized_user_info = UserInfoSerializer(user_info).data + # Temporary fix for getting user role along with user info. + # Proper implementation would be adding role field to UserInfo. + serialized_user_info["is_admin"] = auth_controller.is_admin_by_role( + role.role) + return Response( + status=status.HTTP_200_OK, data={ + "user": serialized_user_info} + ) + except Exception as error: + Logger.error(f"Error while get User : {error}") + return Response( + status=status.HTTP_500_INTERNAL_SERVER_ERROR, + data={"message": "Internal Error"}, + ) + + @action(detail=False, methods=["POST"]) + def invite_user(self, request: Request) -> Response: + serializer = InviteUserSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + user_list = serializer.get_users(serializer.validated_data) + auth_controller = AuthenticationController() + invite_response = auth_controller.invite_user( + admin=request.user, org_id=request.org_id, user_list=user_list + ) + + response_serializer = UserInviteResponseSerializer( + + invite_response, many=True + ) + + if invite_response and len(invite_response) != 0: + response = Response( + status=status.HTTP_200_OK, + data={"message": response_serializer.data}, + ) + else: + response = Response( + status=status.HTTP_400_BAD_REQUEST, + data={"message": "failed"}, + ) + return response + + @action(detail=False, methods=["DELETE"]) + def remove_members_from_organization(self, request: Request) -> Response: + serializer = RemoveUserFromOrganizationSerializer(data=request.data) + + serializer.is_valid(raise_exception=True) + user_emails = serializer.get_user_emails(serializer.validated_data) + organization_id: str = request.org_id + + auth_controller = AuthenticationController() + is_updated = auth_controller.remove_users_from_organization( + admin=request.user, + organization_id=organization_id, + user_emails=user_emails, + ) + if is_updated: + return Response( + status=status.HTTP_200_OK, + data={"status": "success", "message": "success"}, + ) + else: + return Response( + status=status.HTTP_400_BAD_REQUEST, + data={"status": "failed", "message": "failed"}, + ) + + @action(detail=False, methods=["GET"]) + def get_organization_members(self, request: Request) -> Response: + auth_controller = AuthenticationController() + if request.org_id: + members: list[ + OrganizationMember + ] = auth_controller.get_organization_members_by_org_id() + serialized_members = OrganizationMemberSerializer( + members, many=True).data + return Response( + status=status.HTTP_200_OK, + data={"message": "success", "members": serialized_members}, + ) + return Response( + status=status.HTTP_401_UNAUTHORIZED, + data={"message": "cookie not found"}, + ) diff --git a/backend/tenant_account/views.py b/backend/tenant_account/views.py new file mode 100644 index 000000000..1f95d07ae --- /dev/null +++ b/backend/tenant_account/views.py @@ -0,0 +1,87 @@ +import logging +from typing import Any + +from account.authentication_controller import AuthenticationController +from account.dto import UserRoleData +from account.models import Organization +from rest_framework import status +from rest_framework.decorators import api_view +from rest_framework.request import Request +from rest_framework.response import Response +from tenant_account.dto import OrganizationLoginResponse, ResetUserPasswordDto +from tenant_account.serializer import ( + GetRolesResponseSerializer, + OrganizationLoginResponseSerializer, +) + +logger = logging.getLogger(__name__) + + +@api_view(["GET"]) +def logout(request: Request) -> Response: + auth_controller = AuthenticationController() + return auth_controller.user_logout(request) + + +@api_view(["GET"]) +def get_roles(request: Request) -> Response: + auth_controller = AuthenticationController() + roles: list[UserRoleData] = auth_controller.get_user_roles() + serialized_members = GetRolesResponseSerializer(roles, many=True).data + return Response( + status=status.HTTP_200_OK, + data={"message": "success", "members": serialized_members}, + ) + + +@api_view(["POST"]) +def reset_password(request: Request) -> Response: + auth_controller = AuthenticationController() + data: ResetUserPasswordDto = auth_controller.reset_user_password(request.user) + if data.status: + return Response( + status=status.HTTP_200_OK, + data={"status": "success", "message": data.message}, + ) + else: + return Response( + status=status.HTTP_400_BAD_REQUEST, + data={"status": "failed", "message": data.message}, + ) + + +@api_view(["GET"]) +def get_organization(request: Request) -> Response: + auth_controller = AuthenticationController() + try: + org_data = auth_controller.get_organization_info(request.org_id) + if not org_data: + return Response( + status=status.HTTP_404_NOT_FOUND, + data={"message": "Org Not Found"}, + ) + response = makeSignupResponse(org_data) + return Response( + status=status.HTTP_201_CREATED, + data={"message": "success", "organization": response}, + ) + + except Exception as error: + logger.error(f"Error while get User : {error}") + return Response( + status=status.HTTP_500_INTERNAL_SERVER_ERROR, + data={"message": "Internal Error"}, + ) + + +def makeSignupResponse( + organization: Organization, +) -> Any: + return OrganizationLoginResponseSerializer( + OrganizationLoginResponse( + organization.name, + organization.display_name, + organization.organization_id, + organization.created_at, + ) + ).data diff --git a/backend/tool_instance/__init__.py b/backend/tool_instance/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/tool_instance/admin.py b/backend/tool_instance/admin.py new file mode 100644 index 000000000..1e1c975ca --- /dev/null +++ b/backend/tool_instance/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import ToolInstance + +admin.site.register(ToolInstance) diff --git a/backend/tool_instance/apps.py b/backend/tool_instance/apps.py new file mode 100644 index 000000000..1dc6e7b10 --- /dev/null +++ b/backend/tool_instance/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ToolInstanceConfig(AppConfig): + name = "tool_instance" diff --git a/backend/tool_instance/constants.py b/backend/tool_instance/constants.py new file mode 100644 index 000000000..17a3891c5 --- /dev/null +++ b/backend/tool_instance/constants.py @@ -0,0 +1,45 @@ +class ToolInstanceKey: + """Dict keys for ToolInstance model.""" + + PK = "id" + TOOL_ID = "tool_id" + VERSION = "version" + METADATA = "metadata" + STEP = "step" + STATUS = "status" + WORKFLOW = "workflow" + INPUT = "input" + OUTPUT = "output" + TI_COUNT = "tool_instance_count" + + +class JsonSchemaKey: + """Dict Keys for Tool's Json schema.""" + + PROPERTIES = "properties" + THEN = "then" + INPUT_FILE_CONNECTOR = "inputFileConnector" + OUTPUT_FILE_CONNECTOR = "outputFileConnector" + OUTPUT_FOLDER = "outputFolder" + ROOT_FOLDER = "rootFolder" + TENANT_ID = "tenant_id" + INPUT_DB_CONNECTOR = "inputDBConnector" + OUTPUT_DB_CONNECTOR = "outputDBConnector" + ENUM = "enum" + PROJECT_DEFAULT = "Project Default" + + +class ToolInstanceErrors: + TOOL_EXISTS = "Tool with this configuration already exists." + DUPLICATE_API = "It appears that a duplicate call may have been made." + + +class ToolKey: + """Dict keys for a Tool.""" + + NAME = "name" + DESCRIPTION = "description" + ICON = "icon" + FUNCTION_NAME = "function_name" + OUTPUT_TYPE = "output_type" + INPUT_TYPE = "input_type" diff --git a/backend/tool_instance/exceptions.py b/backend/tool_instance/exceptions.py new file mode 100644 index 000000000..75c6d652e --- /dev/null +++ b/backend/tool_instance/exceptions.py @@ -0,0 +1,41 @@ +from typing import Optional + +from rest_framework.exceptions import APIException + + +class ToolInstanceBaseException(APIException): + def __init__( + self, + detail: Optional[str] = None, + code: Optional[int] = None, + tool_name: Optional[str] = None, + ) -> None: + detail = detail or self.default_detail + if tool_name is not None: + detail = f"{detail} Tool: {tool_name}" + super().__init__(detail, code) + + +class ToolFunctionIsMandatory(ToolInstanceBaseException): + status_code = 400 + default_detail = "Tool function is mandatory." + + +class ToolDoesNotExist(ToolInstanceBaseException): + status_code = 400 + default_detail = "Tool doesn't exist." + + +class FetchToolListFailed(ToolInstanceBaseException): + status_code = 400 + default_detail = "Failed to fetch tool list." + + +class ToolInstantiationError(ToolInstanceBaseException): + status_code = 500 + default_detail = "Error instantiating tool." + + +class BadRequestException(ToolInstanceBaseException): + status_code = 400 + default_detail = "Invalid input" diff --git a/backend/tool_instance/migrations/0001_initial.py b/backend/tool_instance/migrations/0001_initial.py new file mode 100644 index 000000000..e0ff6fb73 --- /dev/null +++ b/backend/tool_instance/migrations/0001_initial.py @@ -0,0 +1,136 @@ +# Generated by Django 4.2.1 on 2024-01-23 11:18 + +import uuid + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("connector", "0001_initial"), + ("workflow", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="ToolInstance", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "tool_id", + models.CharField( + db_comment="Function name of the tool being used", + max_length=64, + ), + ), + ( + "input", + models.JSONField( + db_comment="Provisional WF input to a tool", null=True + ), + ), + ( + "output", + models.JSONField( + db_comment="Provisional WF output to a tool", null=True + ), + ), + ("version", models.CharField(max_length=16)), + ( + "metadata", + models.JSONField(db_comment="Stores config for a tool"), + ), + ("step", models.IntegerField()), + ( + "status", + models.CharField(default="Ready to start", max_length=32), + ), + ( + "created_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="created_tools", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "input_db_connector", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="input_db_connector", + to="connector.connectorinstance", + ), + ), + ( + "input_file_connector", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="input_file_connector", + to="connector.connectorinstance", + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="modified_tools", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "output_db_connector", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="output_db_connector", + to="connector.connectorinstance", + ), + ), + ( + "output_file_connector", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="output_file_connector", + to="connector.connectorinstance", + ), + ), + ( + "workflow", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="workflow_tool", + to="workflow.workflow", + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/backend/tool_instance/migrations/__init__.py b/backend/tool_instance/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/tool_instance/models.py b/backend/tool_instance/models.py new file mode 100644 index 000000000..7c9bb5122 --- /dev/null +++ b/backend/tool_instance/models.py @@ -0,0 +1,100 @@ +import uuid + +from account.models import User +from connector.models import ConnectorInstance +from django.db import models +from django.db.models import QuerySet +from utils.models.base_model import BaseModel +from workflow_manager.workflow.models.workflow import Workflow + +TOOL_ID_LENGTH = 64 +TOOL_VERSION_LENGTH = 16 +TOOL_STATUS_LENGTH = 32 + + +class ToolInstanceManager(models.Manager): + def get_instances_for_workflow( + self, workflow: uuid.UUID + ) -> QuerySet["ToolInstance"]: + return self.filter(workflow=workflow) + + +class ToolInstance(BaseModel): + class Status(models.TextChoices): + PENDING = "PENDING", "Settings Not Configured" + READY = "READY", "Ready to Start" + INITIATED = "INITIATED", "Initialization in Progress" + COMPLETED = "COMPLETED", "Process Completed" + ERROR = "ERROR", "Error Encountered" + + workflow = models.ForeignKey( + Workflow, + on_delete=models.CASCADE, + related_name="workflow_tool", + null=False, + blank=False, + ) + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + tool_id = models.CharField( + max_length=TOOL_ID_LENGTH, + db_comment="Function name of the tool being used", + ) + input = models.JSONField( + null=True, db_comment="Provisional WF input to a tool" + ) + output = models.JSONField( + null=True, db_comment="Provisional WF output to a tool" + ) + version = models.CharField(max_length=TOOL_VERSION_LENGTH) + metadata = models.JSONField(db_comment="Stores config for a tool") + step = models.IntegerField() + # TODO: Make as an enum supporting fixed values once we have clarity + status = models.CharField( + max_length=TOOL_STATUS_LENGTH, default="Ready to start" + ) + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="created_tools", + null=True, + blank=True, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="modified_tools", + null=True, + blank=True, + ) + # Added these connectors separately + # for file and db for scalability + input_file_connector = models.ForeignKey( + ConnectorInstance, + on_delete=models.SET_NULL, + related_name="input_file_connector", + null=True, + blank=True, + ) + output_file_connector = models.ForeignKey( + ConnectorInstance, + on_delete=models.SET_NULL, + related_name="output_file_connector", + null=True, + blank=True, + ) + input_db_connector = models.ForeignKey( + ConnectorInstance, + on_delete=models.SET_NULL, + related_name="input_db_connector", + null=True, + blank=True, + ) + output_db_connector = models.ForeignKey( + ConnectorInstance, + on_delete=models.SET_NULL, + related_name="output_db_connector", + null=True, + blank=True, + ) + + objects = ToolInstanceManager() diff --git a/backend/tool_instance/serializers.py b/backend/tool_instance/serializers.py new file mode 100644 index 000000000..0c5241708 --- /dev/null +++ b/backend/tool_instance/serializers.py @@ -0,0 +1,130 @@ +import logging +import uuid +from typing import Any + +from backend.constants import RequestKey +from backend.serializers import AuditSerializer +from prompt_studio.prompt_studio_registry.constants import PromptStudioRegistryKeys +from rest_framework.serializers import ListField, Serializer, UUIDField, ValidationError +from tool_instance.constants import ToolInstanceKey as TIKey +from tool_instance.constants import ToolKey +from tool_instance.exceptions import ToolDoesNotExist +from tool_instance.models import ToolInstance +from tool_instance.tool_instance_helper import ToolInstanceHelper +from tool_instance.tool_processor import ToolProcessor +from unstract.tool_registry.dto import Tool +from workflow_manager.workflow.constants import WorkflowKey +from workflow_manager.workflow.models.workflow import Workflow + +logger = logging.getLogger(__name__) + + +class ToolInstanceSerializer(AuditSerializer): + workflow_id = UUIDField(write_only=True) + + class Meta: + model = ToolInstance + fields = "__all__" + extra_kwargs = { + TIKey.WORKFLOW: { + "required": False, + }, + TIKey.VERSION: { + "required": False, + }, + TIKey.METADATA: { + "required": False, + }, + TIKey.STEP: { + "required": False, + }, + } + + def to_representation(self, instance: ToolInstance) -> dict[str, str]: + rep: dict[str, Any] = super().to_representation(instance) + tool_function = rep.get(TIKey.TOOL_ID) + + if tool_function is None: + raise ToolDoesNotExist() + + tool: Tool = ToolProcessor.get_tool_by_uid(tool_function) + rep[ToolKey.ICON] = tool.icon + rep[ToolKey.NAME] = tool.properties.display_name + # Need to Change it into better method + if self.context.get(RequestKey.REQUEST): + metadata = ToolInstanceHelper.get_altered_metadata(instance) + if metadata: + rep[TIKey.METADATA] = metadata + return rep + + def create(self, validated_data: dict[str, Any]) -> Any: + workflow_id = validated_data.pop(WorkflowKey.WF_ID) + try: + workflow = Workflow.objects.get(pk=workflow_id) + except Workflow.DoesNotExist: + raise ValidationError( + f"Workflow with ID {workflow_id} does not exist." + ) + validated_data[TIKey.WORKFLOW] = workflow + + tool_uid = validated_data.get(TIKey.TOOL_ID) + if not tool_uid: + raise ToolDoesNotExist() + + tool: Tool = ToolProcessor.get_tool_by_uid(tool_uid=tool_uid) + # TODO: Handle other fields once tools SDK is out + validated_data[TIKey.PK] = uuid.uuid4() + # TODO: Use version from tool props + validated_data[TIKey.VERSION] = "" + validated_data[TIKey.METADATA] = { + # TODO: Review and remove tool instance ID + WorkflowKey.WF_TOOL_INSTANCE_ID: str(validated_data[TIKey.PK]), + PromptStudioRegistryKeys.PROMPT_REGISTRY_ID: str(tool_uid), + **ToolProcessor.get_default_settings(tool), + } + if TIKey.STEP not in validated_data: + validated_data[TIKey.STEP] = workflow.workflow_tool.count() + 1 + # Workflow will get activated on adding tools to workflow + if not workflow.is_active: + workflow.is_active = True + workflow.save() + return super().create(validated_data) + + +class ToolInstanceReorderSerializer(Serializer): + workflow_id = UUIDField() + tool_instances = ListField(child=UUIDField()) + + def validate(self, data: dict[str, Any]) -> dict[str, Any]: + workflow_id = data.get(WorkflowKey.WF_ID) + tool_instances = data.get(WorkflowKey.WF_TOOL_INSTANCES, []) + + # Check if the workflow exists + try: + workflow = Workflow.objects.get(pk=workflow_id) + except Workflow.DoesNotExist: + raise ValidationError( + f"Workflow with ID {workflow_id} does not exist." + ) + + # Check if the number of tool instances matches the actual count + tool_instance_count = workflow.workflow_tool.count() + if len(tool_instances) != tool_instance_count: + msg = ( + f"Incorrect number of tool instances passed: " + f"{len(tool_instances)}, expected: {tool_instance_count}" + ) + logger.error(msg) + raise ValidationError(detail=msg) + + # Check if each tool instance exists in the workflow + existing_tool_instance_ids = workflow.workflow_tool.values_list( + "id", flat=True + ) + for tool_instance_id in tool_instances: + if tool_instance_id not in existing_tool_instance_ids: + raise ValidationError( + "One or more tool instances do not exist in the workflow." + ) + + return data diff --git a/backend/tool_instance/tests.py b/backend/tool_instance/tests.py new file mode 100644 index 000000000..a39b155ac --- /dev/null +++ b/backend/tool_instance/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/backend/tool_instance/tool_instance_helper.py b/backend/tool_instance/tool_instance_helper.py new file mode 100644 index 000000000..356d5374d --- /dev/null +++ b/backend/tool_instance/tool_instance_helper.py @@ -0,0 +1,324 @@ +import logging +import os +import uuid +from typing import Any, Optional + +from account.models import User +from adapter_processor.adapter_processor import AdapterProcessor +from adapter_processor.models import AdapterInstance +from connector.connector_instance_helper import ConnectorInstanceHelper +from tool_instance.constants import JsonSchemaKey +from tool_instance.models import ToolInstance +from tool_instance.tool_processor import ToolProcessor +from unstract.adapters.enums import AdapterTypes +from unstract.tool_registry.constants import AdapterPropertyKey +from unstract.tool_registry.dto import Spec, Tool +from unstract.tool_registry.tool_utils import ToolUtils +from workflow_manager.workflow.constants import WorkflowKey + +logger = logging.getLogger(__name__) + + +class ToolInstanceHelper: + @staticmethod + def get_tool_instances_by_workflow( + workflow_id: str, + order_by: str, + lookup: Optional[dict[str, Any]] = None, + offset: Optional[int] = None, + limit: Optional[int] = None, + ) -> list[ToolInstance]: + wf_filter = {} + if lookup: + wf_filter = lookup + wf_filter[WorkflowKey.WF_ID] = workflow_id + + if limit: + offset_value = 0 if not offset else offset + to = offset_value + limit + return list( + ToolInstance.objects.filter(**wf_filter)[ + offset_value:to + ].order_by(order_by) + ) + return list( + ToolInstance.objects.filter(**wf_filter).all().order_by(order_by) + ) + + @staticmethod + def update_instance_metadata( + org_id: str, tool_instance: ToolInstance, metadata: dict[str, Any] + ) -> None: + if ( + JsonSchemaKey.OUTPUT_FILE_CONNECTOR in metadata + and JsonSchemaKey.OUTPUT_FOLDER in metadata + ): + output_connector_name = metadata[ + JsonSchemaKey.OUTPUT_FILE_CONNECTOR + ] + output_connector = ConnectorInstanceHelper.get_output_connector_instance_by_name_for_workflow( # noqa + tool_instance.workflow_id, output_connector_name + ) + if ( + output_connector + and "path" in output_connector.connector_metadata + ): + metadata[JsonSchemaKey.OUTPUT_FOLDER] = os.path.join( + output_connector.connector_metadata["path"], + *(metadata[JsonSchemaKey.OUTPUT_FOLDER].split("/")), + ) + if ( + JsonSchemaKey.INPUT_FILE_CONNECTOR in metadata + and JsonSchemaKey.ROOT_FOLDER in metadata + ): + input_connector_name = metadata[JsonSchemaKey.INPUT_FILE_CONNECTOR] + input_connector = ConnectorInstanceHelper.get_input_connector_instance_by_name_for_workflow( # noqa + tool_instance.workflow_id, input_connector_name + ) + + if input_connector and "path" in input_connector.connector_metadata: + metadata[JsonSchemaKey.ROOT_FOLDER] = os.path.join( + input_connector.connector_metadata["path"], + *(metadata[JsonSchemaKey.ROOT_FOLDER].split("/")), + ) + ToolInstanceHelper.update_metadata_with_adapter_instances( + metadata, tool_instance.tool_id + ) + metadata[JsonSchemaKey.TENANT_ID] = org_id + tool_instance.metadata = metadata + tool_instance.save() + + @staticmethod + def update_metadata_with_adapter_properties( + metadata: dict[str, Any], + adapter_key: str, + adapter_property: dict[str, Any], + adapter_type: AdapterTypes, + ) -> None: + """Update the metadata dictionary with adapter properties. + + Parameters: + metadata (dict[str, Any]): + The metadata dictionary to be updated with adapter properties. + adapter_key (str): + The key in the metadata dictionary corresponding to the adapter. + adapter_property (dict[str, Any]): + The properties of the adapter. + adapter_type (AdapterTypes): + The type of the adapter. + + Returns: + None + """ + if adapter_key in metadata: + adapter_name = metadata[adapter_key] + adapter = AdapterProcessor.get_adapter_by_name_and_type( + adapter_type=adapter_type, adapter_name=adapter_name + ) + adapter_id = str(adapter.id) if adapter else None + metadata_key_for_id = adapter_property.get( + AdapterPropertyKey.ADAPTER_ID_KEY, AdapterPropertyKey.ADAPTER_ID + ) + metadata[metadata_key_for_id] = adapter_id + + @staticmethod + def update_metadata_with_adapter_instances( + metadata: dict[str, Any], tool_uid: str + ) -> None: + """ + Update the metadata dictionary with adapter instances. + Parameters: + metadata (dict[str, Any]): + The metadata dictionary to be updated with adapter instances. + + Returns: + None + """ + tool: Tool = ToolProcessor.get_tool_by_uid(tool_uid=tool_uid) + schema: Spec = ToolUtils.get_json_schema_for_tool(tool) + llm_properties = schema.get_llm_adapter_properties() + embedding_properties = schema.get_embedding_adapter_properties() + vector_db_properties = schema.get_vector_db_adapter_properties() + x2text_properties = schema.get_text_extractor_adapter_properties() + + for adapter_key, adapter_property in llm_properties.items(): + ToolInstanceHelper.update_metadata_with_adapter_properties( + metadata=metadata, + adapter_key=adapter_key, + adapter_property=adapter_property, + adapter_type=AdapterTypes.LLM, + ) + + for adapter_key, adapter_property in embedding_properties.items(): + ToolInstanceHelper.update_metadata_with_adapter_properties( + metadata=metadata, + adapter_key=adapter_key, + adapter_property=adapter_property, + adapter_type=AdapterTypes.EMBEDDING, + ) + + for adapter_key, adapter_property in vector_db_properties.items(): + ToolInstanceHelper.update_metadata_with_adapter_properties( + metadata=metadata, + adapter_key=adapter_key, + adapter_property=adapter_property, + adapter_type=AdapterTypes.VECTOR_DB, + ) + + for adapter_key, adapter_property in x2text_properties.items(): + ToolInstanceHelper.update_metadata_with_adapter_properties( + metadata=metadata, + adapter_key=adapter_key, + adapter_property=adapter_property, + adapter_type=AdapterTypes.X2TEXT, + ) + + @staticmethod + def get_altered_metadata( + tool_instance: ToolInstance, + ) -> Optional[dict[str, Any]]: + """Get altered metadata by resolving relative paths. + + This method retrieves the metadata from the given tool instance + and checks if there are output and input file connectors. + If output and input file connectors exist in the metadata, + it resolves the relative paths using connector instances. + + Args: + tool_instance (ToolInstance). + + Returns: + Optional[dict[str, Any]]: Altered metadata with resolved relative \ + paths. + """ + metadata: dict[str, Any] = tool_instance.metadata + if ( + JsonSchemaKey.OUTPUT_FILE_CONNECTOR in metadata + and JsonSchemaKey.OUTPUT_FOLDER in metadata + ): + output_connector_name = metadata[ + JsonSchemaKey.OUTPUT_FILE_CONNECTOR + ] + output_connector = ConnectorInstanceHelper.get_output_connector_instance_by_name_for_workflow( # noqa + tool_instance.workflow_id, output_connector_name + ) + if ( + output_connector + and "path" in output_connector.connector_metadata + ): + relative_path = ToolInstanceHelper.get_relative_path( + metadata[JsonSchemaKey.OUTPUT_FOLDER], + output_connector.connector_metadata["path"], + ) + metadata[JsonSchemaKey.OUTPUT_FOLDER] = relative_path + if ( + JsonSchemaKey.INPUT_FILE_CONNECTOR in metadata + and JsonSchemaKey.ROOT_FOLDER in metadata + ): + input_connector_name = metadata[JsonSchemaKey.INPUT_FILE_CONNECTOR] + input_connector = ConnectorInstanceHelper.get_input_connector_instance_by_name_for_workflow( # noqa + tool_instance.workflow_id, input_connector_name + ) + if input_connector and "path" in input_connector.connector_metadata: + relative_path = ToolInstanceHelper.get_relative_path( + metadata[JsonSchemaKey.ROOT_FOLDER], + input_connector.connector_metadata["path"], + ) + metadata[JsonSchemaKey.ROOT_FOLDER] = relative_path + return metadata + + @staticmethod + def update_metadata_with_default_adapter( + adapter_type: AdapterTypes, + schema_spec: Spec, + adapter: AdapterInstance, + metadata: dict[str, Any], + ) -> None: + """Update the metadata of a tool instance with default values for + enabled adapters. + + Parameters: + adapter_type (AdapterTypes): The type of adapter to update + the metadata for. + schema_spec (Spec): The schema specification for the tool. + adapter (AdapterInstance): The adapter instance to use for updating + the metadata. + metadata (dict[str, Any]): The metadata dictionary to update. + + Returns: + None + """ + properties = {} + if adapter_type == AdapterTypes.LLM: + properties = schema_spec.get_llm_adapter_properties() + if adapter_type == AdapterTypes.EMBEDDING: + properties = schema_spec.get_embedding_adapter_properties() + if adapter_type == AdapterTypes.VECTOR_DB: + properties = schema_spec.get_vector_db_adapter_properties() + if adapter_type == AdapterTypes.X2TEXT: + properties = schema_spec.get_text_extractor_adapter_properties() + for adapter_key, adapter_property in properties.items(): + metadata_key_for_id = adapter_property.get( + AdapterPropertyKey.ADAPTER_ID_KEY, AdapterPropertyKey.ADAPTER_ID + ) + metadata[adapter_key] = adapter.adapter_name + metadata[metadata_key_for_id] = str(adapter.id) + + @staticmethod + def update_metadata_with_default_values( + tool_instance: ToolInstance, user: User + ) -> None: + """Update the metadata of a tool instance with default values for + enabled adapters. + + Parameters: + tool_instance (ToolInstance): The tool instance to update the + metadata. + + Returns: + None + """ + metadata: dict[str, Any] = tool_instance.metadata + tool_uuid = tool_instance.tool_id + + tool: Tool = ToolProcessor.get_tool_by_uid(tool_uid=tool_uuid) + schema: Spec = ToolUtils.get_json_schema_for_tool(tool) + + default_adapters = AdapterProcessor.get_default_adapters(user=user) + for adapter in default_adapters: + try: + adapter_type = AdapterTypes(adapter.adapter_type) + ToolInstanceHelper.update_metadata_with_default_adapter( + adapter_type=adapter_type, + schema_spec=schema, + adapter=adapter, + metadata=metadata, + ) + except ValueError: + logger.warning(f"Invalid AdapterType {adapter.adapter_type}") + tool_instance.metadata = metadata + tool_instance.save() + + @staticmethod + def get_relative_path(absolute_path: str, base_path: str) -> str: + if absolute_path.startswith(base_path): + relative_path = os.path.relpath(absolute_path, base_path) + else: + relative_path = absolute_path + if relative_path == ".": + relative_path = "" + return relative_path + + @staticmethod + def reorder_tool_instances(instances_to_reorder: list[uuid.UUID]) -> None: + """Reorders tool instances based on the list of tool UUIDs received. + Saves the instance in the DB. + + Args: + instances_to_reorder (list[uuid.UUID]): Desired order of tool UUIDs + """ + logger.info(f"Reordering instances: {instances_to_reorder}") + for step, tool_instance_id in enumerate(instances_to_reorder): + tool_instance = ToolInstance.objects.get(pk=tool_instance_id) + tool_instance.step = step + 1 + tool_instance.save() diff --git a/backend/tool_instance/tool_processor.py b/backend/tool_instance/tool_processor.py new file mode 100644 index 000000000..68c3dd10d --- /dev/null +++ b/backend/tool_instance/tool_processor.py @@ -0,0 +1,140 @@ +import logging +from typing import Any, Optional + +from account.models import User +from adapter_processor.adapter_processor import AdapterProcessor +from prompt_studio.prompt_studio_registry.prompt_studio_registry_helper import ( + PromptStudioRegistryHelper, +) +from tool_instance.exceptions import ToolDoesNotExist +from unstract.adapters.enums import AdapterTypes +from unstract.tool_registry.dto import Spec, Tool +from unstract.tool_registry.tool_registry import ToolRegistry +from unstract.tool_registry.tool_utils import ToolUtils + +logger = logging.getLogger(__name__) + + +class ToolProcessor: + TOOL_NOT_IN_REGISTRY_MESSAGE = "Tool does not exist in registry" + tool_registry = ToolRegistry() + + @staticmethod + def get_tool_by_uid(tool_uid: str) -> Tool: + """Function to get and instantiate a tool for a given tool + settingsId.""" + tool_registry = ToolRegistry() + tool: Optional[Tool] = tool_registry.get_tool_by_uid(tool_uid) + # HACK: Assume tool_uid is prompt_registry_id for fetching a dynamic + # tool made with Prompt Studio. + if not tool: + tool = PromptStudioRegistryHelper.get_tool_by_prompt_registry_id( + prompt_registry_id=tool_uid + ) + if not tool: + raise ToolDoesNotExist( + f"{ToolProcessor.TOOL_NOT_IN_REGISTRY_MESSAGE}: {tool_uid}" + ) + return tool + + @staticmethod + def get_default_settings(tool: Tool) -> dict[str, str]: + """Function to make and fill settings with default values. + + Args: + tool (ToolSettings): tool + + Returns: + dict[str, str]: tool settings + """ + tool_metadata: dict[str, str] = ToolUtils.get_default_settings(tool) + return tool_metadata + + @staticmethod + def get_json_schema_for_tool(tool_uid: str, user: User) -> dict[str, str]: + """Function to Get JSON Schema for Tools.""" + tool: Tool = ToolProcessor.get_tool_by_uid(tool_uid=tool_uid) + schema: Spec = ToolUtils.get_json_schema_for_tool(tool) + ToolProcessor.update_schema_with_adapter_configurations( + schema=schema, user=user + ) + schema_json: dict[str, Any] = schema.to_dict() + return schema_json + + @staticmethod + def update_schema_with_adapter_configurations( + schema: Spec, user: User + ) -> None: + """Updates the JSON schema with the available adapter configurations + for the LLM, embedding, and vector DB adapters. + + Args: + schema (Spec): The JSON schema object to be updated. + + Returns: + None. The `schema` object is updated in-place. + """ + llm_keys = schema.get_llm_adapter_properties_keys() + embedding_keys = schema.get_embedding_adapter_properties_keys() + vector_db_keys = schema.get_vector_db_adapter_properties_keys() + x2text_keys = schema.get_text_extractor_adapter_properties_keys() + + if llm_keys: + adapters = AdapterProcessor.get_adapters_by_type( + AdapterTypes.LLM, user=user + ) + for key in llm_keys: + adapter_names = map( + lambda adapter: str(adapter.adapter_name), adapters + ) + schema.properties[key]["enum"] = list(adapter_names) + + if embedding_keys: + adapters = AdapterProcessor.get_adapters_by_type( + AdapterTypes.EMBEDDING, user=user + ) + for key in embedding_keys: + adapter_names = map( + lambda adapter: str(adapter.adapter_name), adapters + ) + schema.properties[key]["enum"] = list(adapter_names) + + if vector_db_keys: + adapters = AdapterProcessor.get_adapters_by_type( + AdapterTypes.VECTOR_DB, user=user + ) + for key in vector_db_keys: + adapter_names = map( + lambda adapter: str(adapter.adapter_name), adapters + ) + schema.properties[key]["enum"] = list(adapter_names) + + if x2text_keys: + adapters = AdapterProcessor.get_adapters_by_type( + AdapterTypes.X2TEXT, user=user + ) + for key in x2text_keys: + adapter_names = map( + lambda adapter: str(adapter.adapter_name), adapters + ) + schema.properties[key]["enum"] = list(adapter_names) + + @staticmethod + def get_tool_list() -> list[dict[str, Any]]: + """Function to get a list of tools.""" + tool_registry = ToolRegistry() + prompt_studio_tools: list[ + dict[str, Any] + ] = PromptStudioRegistryHelper.fetch_json_for_registry() + tool_list: list[ + dict[str, Any] + ] = tool_registry.fetch_tools_descriptions() + tool_list = tool_list + prompt_studio_tools + return tool_list + + @staticmethod + def get_registry_tools() -> list[Tool]: + """Function to get a list of tools.""" + tool_registry = ToolRegistry() + tool_list: list[Tool] = tool_registry.fetch_all_tools() + return tool_list diff --git a/backend/tool_instance/urls.py b/backend/tool_instance/urls.py new file mode 100644 index 000000000..dbcb75189 --- /dev/null +++ b/backend/tool_instance/urls.py @@ -0,0 +1,46 @@ +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns +from tool_instance.views import ToolInstanceViewSet + +from . import views + +tool_instance_list = ToolInstanceViewSet.as_view( + { + "get": "list", + "post": "create", + } +) +tool_instance_detail = ToolInstanceViewSet.as_view( + # fmt: off + { + "get": "retrieve", + "put": "update", + "patch": "partial_update", + "delete": "destroy" + } + # fmt: on +) + +tool_instance_reorder = ToolInstanceViewSet.as_view({"post": "reorder"}) + +urlpatterns = format_suffix_patterns( + [ + path("tool_instance/", tool_instance_list, name="tool-instance-list"), + path( + "tool_instance//", + tool_instance_detail, + name="tool-instance-detail", + ), + path( + "tool_settings_schema/", + views.tool_settings_schema, + name="tool_settings_schema", + ), + path( + "tool_instance/reorder/", + tool_instance_reorder, + name="tool_instance_reorder", + ), + path("tool/", views.get_tool_list, name="tool_list"), + ] +) diff --git a/backend/tool_instance/views.py b/backend/tool_instance/views.py new file mode 100644 index 000000000..02bc58768 --- /dev/null +++ b/backend/tool_instance/views.py @@ -0,0 +1,172 @@ +import logging +import uuid +from typing import Any + +from account.custom_exceptions import DuplicateData +from backend.constants import RequestKey +from django.db import IntegrityError +from django.db.models.query import QuerySet +from rest_framework import serializers, status, viewsets +from rest_framework.decorators import api_view +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning +from tool_instance.constants import ToolInstanceErrors +from tool_instance.constants import ToolInstanceKey as TIKey +from tool_instance.constants import ToolKey +from tool_instance.exceptions import FetchToolListFailed, ToolFunctionIsMandatory +from tool_instance.models import ToolInstance +from tool_instance.serializers import ( + ToolInstanceReorderSerializer as TIReorderSerializer, +) +from tool_instance.serializers import ToolInstanceSerializer +from tool_instance.tool_instance_helper import ToolInstanceHelper +from tool_instance.tool_processor import ToolProcessor +from utils.filtering import FilterHelper +from workflow_manager.workflow.constants import WorkflowKey + +logger = logging.getLogger(__name__) + + +@api_view(["GET"]) +def tool_settings_schema(request: Request) -> Response: + if request.method == "GET": + tool_function = request.GET.get(ToolKey.FUNCTION_NAME) + if tool_function is None or tool_function == "": + raise ToolFunctionIsMandatory() + + json_schema = ToolProcessor.get_json_schema_for_tool( + tool_uid=tool_function, user=request.user + ) + return Response(data=json_schema, status=status.HTTP_200_OK) + + +@api_view(("GET",)) +def get_tool_list(request: Request) -> Response: + """Get tool list. + + Fetches a list of tools available in the Tool registry + """ + if request.method == "GET": + try: + logger.info("Fetching tools from the tool registry...") + return Response( + data=ToolProcessor.get_tool_list(), status=status.HTTP_200_OK + ) + except Exception as exc: + logger.error(f"Failed to fetch tools: {exc}") + raise FetchToolListFailed + + +class ToolInstanceViewSet(viewsets.ModelViewSet): + versioning_class = URLPathVersioning + queryset = ToolInstance.objects.all() + serializer_class = ToolInstanceSerializer + + def get_queryset(self) -> QuerySet: + filterArgs = FilterHelper.build_filter_args( + self.request, + RequestKey.PROJECT, + RequestKey.CREATED_BY, + RequestKey.WORKFLOW, + ) + if filterArgs: + queryset = ToolInstance.objects.filter( + created_by=self.request.user, **filterArgs + ) + else: + queryset = ToolInstance.objects.filter(created_by=self.request.user) + return queryset + + def get_serializer_class(self) -> serializers.Serializer: + if self.action == "reorder": + return TIReorderSerializer + else: + return ToolInstanceSerializer + + def create(self, request: Any) -> Response: + """Create tool instance. + + Creates a tool instance, useful to add them directly to a + workflow. Its an alternative to creating tool instances through + the LLM response. + """ + + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + try: + self.perform_create(serializer) + except IntegrityError: + raise DuplicateData( + f"{ToolInstanceErrors.TOOL_EXISTS}, " + f"{ToolInstanceErrors.DUPLICATE_API}" + ) + instance: ToolInstance = serializer.instance + ToolInstanceHelper.update_metadata_with_default_values( + instance, user=request.user + ) + headers = self.get_success_headers(serializer.data) + return Response( + serializer.data, status=status.HTTP_201_CREATED, headers=headers + ) + + def perform_destroy(self, instance: ToolInstance) -> None: + """Deletes a tool instance and decrements successor instance's steps. + + Args: + instance (ToolInstance): Instance being deleted. + """ + lookup = {"step__gt": instance.step} + next_tool_instances: list[ + ToolInstance + ] = ToolInstanceHelper.get_tool_instances_by_workflow( + instance.workflow.id, TIKey.STEP, lookup=lookup + ) + super().perform_destroy(instance) + + for instance in next_tool_instances: + instance.step = instance.step - 1 + instance.save() + return + + def partial_update( + self, request: Request, *args: Any, **kwargs: Any + ) -> Response: + """Allows partial updates on a tool instance.""" + instance: ToolInstance = self.get_object() + serializer = self.get_serializer( + instance, data=request.data, partial=True + ) + serializer.is_valid(raise_exception=True) + if serializer.validated_data.get(TIKey.METADATA): + metadata: dict[str, Any] = serializer.validated_data.get( + TIKey.METADATA + ) + + # TODO: Move update logic into serializer + ToolInstanceHelper.update_instance_metadata( + request.org_id, instance, metadata + ) + return Response(serializer.data) + return super().partial_update(request, *args, **kwargs) + + def reorder(self, request: Any, **kwargs: Any) -> Response: + """Reorder tool instances. + + Reorders the tool instances based on a list of UUIDs. + """ + serializer: TIReorderSerializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + wf_id = serializer.validated_data[WorkflowKey.WF_ID] + instances_to_reorder: list[uuid.UUID] = serializer.validated_data[ + WorkflowKey.WF_TOOL_INSTANCES + ] + + ToolInstanceHelper.reorder_tool_instances(instances_to_reorder) + tool_instances = ToolInstance.objects.get_instances_for_workflow( + workflow=wf_id + ) + ti_serializer = ToolInstanceSerializer( + instance=tool_instances, many=True + ) + return Response(ti_serializer.data, status=status.HTTP_200_OK) diff --git a/backend/utils/__init__.py b/backend/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/utils/common_utils.py b/backend/utils/common_utils.py new file mode 100644 index 000000000..8db14369e --- /dev/null +++ b/backend/utils/common_utils.py @@ -0,0 +1,23 @@ +from enum import Enum + + +class CommonUtils: + @staticmethod + def str_to_bool(string: str) -> bool: + """String value of boolean to boolean. + + Args: + string (str): value like "true", "True" etc.. + + Returns: + bool + """ + return string.lower() == "true" + + +class ModelEnum(Enum): + @classmethod + def choices(cls) -> list[tuple[str, str]]: + """Class method implementing model.TextChoice's choices() to enable + using an enum in a model.""" + return [(key.value, key.name) for key in cls] diff --git a/backend/utils/constants.py b/backend/utils/constants.py new file mode 100644 index 000000000..d12cbf6d8 --- /dev/null +++ b/backend/utils/constants.py @@ -0,0 +1,9 @@ +class Account: + CREATED_BY = "created_by" + MODIFIED_BY = "modified_by" + + +class Common: + METADATA = "metadata" + MODULE = "module" + CONNECTOR = "connector" diff --git a/backend/utils/filtering.py b/backend/utils/filtering.py new file mode 100644 index 000000000..99e6b7df0 --- /dev/null +++ b/backend/utils/filtering.py @@ -0,0 +1,21 @@ +from rest_framework.request import Request + + +class FilterHelper: + @staticmethod + def build_filter_args(request: Request, *params: str) -> dict[str, str]: + """Builds a dict of filter to pass to the QueryManager from the + request. + + Args: + request (Request): Request to obtain query from + + Returns: + dict[str, str]: Filter dict to pass to request + """ + filter_args: dict[str, str] = {} + for queryParam in params: + paramValue = request.query_params.get(queryParam) + if paramValue is not None: + filter_args[queryParam] = paramValue + return filter_args diff --git a/backend/utils/models/base_model.py b/backend/utils/models/base_model.py new file mode 100644 index 000000000..b26f0f67d --- /dev/null +++ b/backend/utils/models/base_model.py @@ -0,0 +1,9 @@ +from django.db import models + + +class BaseModel(models.Model): + created_at = models.DateTimeField(auto_now_add=True) + modified_at = models.DateTimeField(auto_now=True) + + class Meta: + abstract = True diff --git a/backend/utils/request/__init__.py b/backend/utils/request/__init__.py new file mode 100644 index 000000000..fc352da4a --- /dev/null +++ b/backend/utils/request/__init__.py @@ -0,0 +1,3 @@ +from .request import HTTPMethod, make_http_request + +__all__ = ["make_http_request", "HTTPMethod"] diff --git a/backend/utils/request/constants.py b/backend/utils/request/constants.py new file mode 100644 index 000000000..217325d13 --- /dev/null +++ b/backend/utils/request/constants.py @@ -0,0 +1,8 @@ +class RequestConstants: + """Constants used for make_http_request().""" + + VERB = "verb" + URL = "url" + HEADERS = "headers" + PARAMS = "params" + DATA = "data" diff --git a/backend/utils/request/feature_flag.py b/backend/utils/request/feature_flag.py new file mode 100644 index 000000000..a62d5a790 --- /dev/null +++ b/backend/utils/request/feature_flag.py @@ -0,0 +1,40 @@ +"""Feature flag utils file.""" + +from typing import Optional + +from unstract.flags.client import EvaluationClient + + +def check_feature_flag_status( + flag_key: str, + namespace_key: str = "default", + entity_id: str = "unstract", + context: Optional[dict[str, str]] = None, +) -> bool: + """Check the status of a feature flag for a given entity. + + Args: + namespace_key (str): The namespace key of the feature flag. + flag_key (str): The flag key of the feature flag. + entity_id (str): The ID of the entity for which the feature flag status + is checked. + context (dict, optional): Additional context data for evaluating the + feature flag. Defaults to None. + + Returns: + bool: + True if the feature flag is enabled for the entity, False otherwise. + """ + + try: + evaluation_client = EvaluationClient() + response = evaluation_client.boolean_evaluate_feature_flag( + namespace_key=namespace_key, + flag_key=flag_key, + entity_id=entity_id, + context=context, + ) + return bool(response) # Wrap the response in a boolean check + except Exception as e: + print(f"Error: {str(e)}") + return False diff --git a/backend/utils/request/request.py b/backend/utils/request/request.py new file mode 100644 index 000000000..9c05df155 --- /dev/null +++ b/backend/utils/request/request.py @@ -0,0 +1,49 @@ +import logging +from enum import Enum +from typing import Any, Optional + +import requests as pyrequests +from requests.exceptions import RequestException + +logger = logging.getLogger(__name__) + + +class HTTPMethod(Enum): + GET = "GET" + POST = "POST" + DELETE = "DELETE" + PUT = "PUT" + PATCH = "PATCH" + + +def make_http_request( + verb: HTTPMethod, + url: str, + data: Optional[dict[str, Any]] = None, + headers: Optional[dict[str, Any]] = None, + params: Optional[dict[str, Any]] = None, +) -> str: + """Generic helper function to help make a HTTP request.""" + try: + if verb == HTTPMethod.GET: + response = pyrequests.get(url, params=params, headers=headers) + elif verb == HTTPMethod.POST: + response = pyrequests.post(url, json=data, params=params, headers=headers) + elif verb == HTTPMethod.DELETE: + response = pyrequests.delete(url, params=params, headers=headers) + else: + raise ValueError("Invalid HTTP verb. Supported verbs: GET, POST, DELETE") + + response.raise_for_status() + return_val: str = ( + response.json() + if response.headers.get("content-type") == "application/json" + else response.text + ) + return return_val + except RequestException as e: + logger.error(f"HTTP request error: {e}") + raise e + except Exception as e: + logger.error(f"An unexpected error occurred: {e}") + raise e diff --git a/backend/utils/seed_data/README.md b/backend/utils/seed_data/README.md new file mode 100644 index 000000000..8998c2a54 --- /dev/null +++ b/backend/utils/seed_data/README.md @@ -0,0 +1,27 @@ +# Generating fixtures for tests + +Seeding data into the DB can help create fixtures to run tests with a custom set of records that gets reset after every run. + +## Seeding + +In order to seed data into the DB for the first time, we update and make use of `seed_data.py` to create the necessary records. + +Run the following to insert records. + +``` +python manage.py shell < utils/seed_data/seed_data.py +``` + +## Fixture generation + +The inserted records/state needs to be dumped to a fixture with the following + +``` +python manage.py dumpdata --indent 4 > .json +``` + +Subsequently this can be used to load data (or) reset back to this initial state with the following + +``` +python manage.py loaddata .json +``` diff --git a/backend/utils/seed_data/seed_data.py b/backend/utils/seed_data/seed_data.py new file mode 100644 index 000000000..94c17345b --- /dev/null +++ b/backend/utils/seed_data/seed_data.py @@ -0,0 +1,61 @@ +# Usage : python manage.py shell < api/utils/seed_data/seed_data.py + +from account.models import Organization, User +from project.models import Project +from prompt.models import Prompt + +try: + # Creating org + zipOrg = Organization.objects.create(org_name="Zipstack") + + # Creating users and updating Orgs with FK + rootUser = User.objects.create( + org=zipOrg, + email="johndoe@gmail.com", + first_name="John", + last_name="Doe", + is_admin=True, + ) + Organization.objects.filter(org_name__exact="Zipstack").update( + created_by=rootUser, modified_by=rootUser + ) + staffUser = User.objects.create( + org=zipOrg, + email="user1@gmail.com", + first_name="Ron", + last_name="Stone", + is_admin=False, + created_by=rootUser, + modified_by=rootUser, + ) + + # Creating a project + zipProject = Project.objects.create( + org=zipOrg, + project_name="Unstract Test", + created_by=staffUser, + modified_by=staffUser, + ) + + # Creating some prompts + prompt1 = Prompt.objects.create( + org=zipOrg, + project=zipProject, + version_name="v0.1.0", + created_by=staffUser, + modified_by=staffUser, + prompt_input="You are a Django programmer, write a REST API \ + to support CRUD on a simple model", + ) + + prompt2 = Prompt.objects.create( + org=zipOrg, + project=zipProject, + version_name="v0.1.1", + created_by=staffUser, + modified_by=staffUser, + prompt_input="You are a poet (William Wordsworth), write a \ + poem on generative AI", + ) +except Exception as e: + print("Exception while seeding data: ", e) diff --git a/backend/utils/serializer_utils.py b/backend/utils/serializer_utils.py new file mode 100644 index 000000000..2534404a4 --- /dev/null +++ b/backend/utils/serializer_utils.py @@ -0,0 +1,31 @@ +from typing import Any + +from account.models import User +from rest_framework.request import Request +from utils.constants import Account + + +class SerializerUtils: + @staticmethod + def check_context_for_GET_or_POST(context: dict[str, Any]) -> bool: + """Checks the context. + + Args: + context (str): _description_ + + Returns: + bool: _description_ + """ + request: Request = context.get("request") + if request and request.method in ("GET", "POST"): + return True + else: + return False + + @staticmethod + def update_created_and_modified_fields( + validated_data: dict[str, Any], user: User, created_by: bool = False + ) -> None: + if created_by: + validated_data.update({Account.CREATED_BY: user}) + validated_data.update({Account.MODIFIED_BY: user}) diff --git a/backend/workflow_manager/__init__.py b/backend/workflow_manager/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/workflow_manager/endpoint/__init__.py b/backend/workflow_manager/endpoint/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/workflow_manager/endpoint/admin.py b/backend/workflow_manager/endpoint/admin.py new file mode 100644 index 000000000..846f6b406 --- /dev/null +++ b/backend/workflow_manager/endpoint/admin.py @@ -0,0 +1 @@ +# Register your models here. diff --git a/backend/workflow_manager/endpoint/apps.py b/backend/workflow_manager/endpoint/apps.py new file mode 100644 index 000000000..e880bba6f --- /dev/null +++ b/backend/workflow_manager/endpoint/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class WorkflowEndpointConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "workflow_manager.endpoint" diff --git a/backend/workflow_manager/endpoint/base_connector.py b/backend/workflow_manager/endpoint/base_connector.py new file mode 100644 index 000000000..f6e782fcd --- /dev/null +++ b/backend/workflow_manager/endpoint/base_connector.py @@ -0,0 +1,96 @@ +import json +from typing import Any + +from django.conf import settings +from django.db import connection +from fsspec import AbstractFileSystem +from unstract.connectors.filesystems import connectors +from unstract.connectors.filesystems.unstract_file_system import ( + UnstractFileSystem, +) +from unstract.workflow_execution.execution_file_handler import ( + ExecutionFileHandler, +) +from utils.constants import Common + + +class BaseConnector(ExecutionFileHandler): + """Base class for connectors providing common methods and utilities.""" + + def __init__( + self, workflow_id: str, execution_id: str, organization_id: str + ) -> None: + """Initialize the BaseConnector class. + + This class serves as a base for connectors and provides common + utilities. + """ + if not (settings.API_STORAGE_DIR and settings.WORKFLOW_DATA_DIR): + raise ValueError("Missed env API_STORAGE_DIR or WORKFLOW_DATA_DIR") + super().__init__(workflow_id, execution_id, organization_id) + # Directory path for storing execution-related files for API + self.api_storage_dir: str = self.create_execution_dir_path( + workflow_id, execution_id, organization_id, settings.API_STORAGE_DIR + ) + + def get_fsspec( + self, settings: dict[str, Any], connector_id: str + ) -> AbstractFileSystem: + """Get an fsspec file system based on the specified connector. + + Parameters: + - settings (dict): Connector-specific settings. + - connector_id (str): Identifier for the desired connector. + + Returns: + AbstractFileSystem: An fsspec file system instance. + + Raises: + KeyError: If the connector_id is not found in the connectors dictionary. + """ + if connector_id not in connectors: + raise ValueError(f"Invalid connector_id: {connector_id}") + connector = connectors[connector_id][Common.METADATA][Common.CONNECTOR] + connector_class: UnstractFileSystem = connector(settings) + return connector_class.get_fsspec_fs() + + @classmethod + def get_json_schema(cls, file_path: str) -> dict[str, Any]: + """Load and return a JSON schema from the specified file path. + + Parameters: + - file_path (str): The path to the JSON schema file. + + Returns: + dict: The loaded JSON schema. + + Raises: + json.JSONDecodeError: If there is an issue decoding the JSON file. + """ + try: + with open(file_path, encoding="utf-8") as file: + schema: dict[str, Any] = json.load(file) + except OSError: + schema = {} + return schema + + @classmethod + def get_api_storage_dir_path( + cls, workflow_id: str, execution_id: str + ) -> str: + """Get the directory path for storing api files. + + Parameters: + - workflow_id (str): Identifier for the workflow. + - execution_id (str): Identifier for the execution. + - organization_id (Optional[str]): Identifier for the organization + (default: None). + + Returns: + str: The directory path for the execution. + """ + organization_id = connection.tenant.schema_name + api_storage_dir: str = cls.create_execution_dir_path( + workflow_id, execution_id, organization_id, settings.API_STORAGE_DIR + ) + return api_storage_dir diff --git a/backend/workflow_manager/endpoint/constants.py b/backend/workflow_manager/endpoint/constants.py new file mode 100644 index 000000000..c2ffe5072 --- /dev/null +++ b/backend/workflow_manager/endpoint/constants.py @@ -0,0 +1,85 @@ +class TableColumns: + CREATED_BY = "created_by" + CREATED_AT = "created_at" + + +class DBConnectionClass: + SNOWFLAKE = "SnowflakeConnection" + + +class Snowflake: + COLUMN_TYPES = [ + "VARCHAR", + "CHAR", + "CHARACTER", + "STRING", + "TEXT", + "BINARY", + "VARBINARY", + "DATE", + "DATETIME", + "TIME", + "TIMESTAMP", + "TIMESTAMP_LTZ", + "TIMESTAMP_NTZ", + "TIMESTAMP_TZ", + "BOOLEAN", + ] + + +class FileSystemConnector: + MAX_FILES = 100 + + +class WorkflowFileType: + SOURCE = "SOURCE" + INFILE = "INFILE" + METADATA_JSON = "METADATA.json" + + +class SourceKey: + FILE_EXTENSIONS = "fileExtensions" + PROCESS_SUB_DIRECTORIES = "processSubDirectories" + MAX_FILES = "maxFiles" + ROOT_FOLDER = "rootFolder" + + +class DestinationKey: + TABLE = "table" + INCLUDE_AGENT = "includeAgent" + INCLUDE_TIMESTAMP = "includeTimestamp" + AGENT_NAME = "agentName" + COLUMN_MODE = "columnMode" + SINGLE_COLUMN_NAME = "singleColumnName" + PATH = "path" + OUTPUT_FOLDER = "outputFolder" + OVERWRITE_OUTPUT_DOCUMENT = "overwriteOutput" + + +class OutputJsonKey: + JSON_RESULT_KEY = "result" + + +class FileType: + PDF_DOCUMENTS = "PDF documents" + TEXT_DOCUMENTS = "Text documents" + WORD_DOCUMENTS = "Word documents" + OPENOFFICE_DOCUMENTS = "Openoffice documents" + IMAGES = "Images" + + +class FilePattern: + PDF_DOCUMENTS = ["*.pdf"] + TEXT_DOCUMENTS = ["*.txt"] + WORD_DOCUMENTS = ["*.doc", "*.docx"] + OPENOFFICE_DOCUMENTS = ["*.odt"] + IMAGES = ["*.jpg", "*.jpeg", "*.png", "*.gif", "*.bmp"] + + +class SourceConstant: + MAX_RECURSIVE_DEPTH = 10 + + +class ApiDeploymentResultStatus: + SUCCESS = "Success" + FAILED = "Failed" diff --git a/backend/workflow_manager/endpoint/database_utils.py b/backend/workflow_manager/endpoint/database_utils.py new file mode 100644 index 000000000..234493bda --- /dev/null +++ b/backend/workflow_manager/endpoint/database_utils.py @@ -0,0 +1,268 @@ +import datetime +import json +import logging +from typing import Any, Optional + +from unstract.connectors.databases import connectors as db_connectors +from unstract.connectors.databases.unstract_db import UnstractDB +from utils.constants import Common +from workflow_manager.endpoint.constants import ( + DBConnectionClass, + Snowflake, + TableColumns, +) +from workflow_manager.workflow.enums import AgentName, ColumnModes + +logger = logging.getLogger(__name__) + + +class DatabaseUtils: + @staticmethod + def make_sql_values_for_query( + values: dict[str, Any], column_types: dict[str, str], cls: Any = None + ) -> list[str]: + """Making Sql Values for Query. + + Args: + values (dict[str, Any]): dictionary of columns and values + column_types (dict[str,str]): types of columns + cls (Any, optional): The database connection class (e.g., + DBConnectionClass.SNOWFLAKE) for handling database-specific + queries. + Defaults to None. + + Returns: + list[str]: _description_ + + Note: + - If `cls` is not provided or is None, the function assumes a + Default SQL database and makes values accordingly. + - If `cls` is provided and matches DBConnectionClass.SNOWFLAKE, + the function makes values using Snowflake-specific syntax. + """ + sql_values: list[str] = [] + for column in values: + if cls == DBConnectionClass.SNOWFLAKE: + col = column.lower() + type_x = column_types[col] + if type_x in Snowflake.COLUMN_TYPES: + sql_values.append(f"'{values[column]}'") + elif type_x == "VARIANT": + values[column] = values[column].replace("'", "\\'") + sql_values.append(f"parse_json($${values[column]}$$)") + else: + sql_values.append(f"{values[column]}") + else: + # Default to Other SQL DBs + # TODO: Handle numeric types with no quotes + sql_values.append(f"'{values[column]}'") + + return sql_values + + @staticmethod + def get_column_types( + engine: Any, table_name: str, cls: Any = None + ) -> dict[str, str]: + """Retrieve column types for a specified table from a database engine. + + Args: + engine (Any): The database engine used to execute queries. + table_name (str): The name of the table for which column types + are retrieved. + cls (Any, optional): The database connection class (e.g., + DBConnectionClass.SNOWFLAKE) for handling database-specific + queries. + Defaults to None. + + Returns: + dict: A dictionary mapping column names to their respective data + types. + + Raises: + Exception: If there is an error while retrieving column types, + an exception is raised. Exit. + + Note: + - If `cls` is not provided or is None, the function assumes a + Default SQL database and queries column types accordingly. + - If `cls` is provided and matches DBConnectionClass.SNOWFLAKE, + the function queries column types using Snowflake-specific + syntax. + """ + try: + column_types: dict[str, str] = {} + with engine.cursor() as cursor: + if cls == DBConnectionClass.SNOWFLAKE: + results = cursor.execute(f"describe table {table_name}") + for column in results: + column_types[column[0].lower()] = column[1].split("(")[ + 0 + ] + else: + # Default to Other SQL DBs + # Postgresql treats the table names as in lowercase + # tested only with Postgresql + table_name = str.lower(table_name) + columns_with_types_query = ( + "SELECT column_name, data_type FROM " + "information_schema.columns WHERE " + f"table_name = '{table_name}'" + ) + cursor.execute(columns_with_types_query) + columns_with_types = cursor.fetchall() + for column_name, data_type in columns_with_types: + column_types[column_name] = data_type + except Exception as e: + logger.error( + f"Error getting column types for {table_name}: {str(e)}" + ) + raise e + return column_types + + @staticmethod + def get_columns_and_values( + column_mode_str: str, + data: Any, + include_timestamp: bool = False, + include_agent: bool = False, + agent_name: Optional[str] = AgentName.UNSTRACT_DBWRITER.value, + single_column_name: str = "data", + ) -> dict[str, Any]: + """Generate a dictionary of columns and values based on specified + parameters. + + Args: + column_mode_str (str): The string representation of the column mode, + which determines how data is stored in the dictionary. + data (Any): The data to be stored in the dictionary. + include_timestamp (bool, optional): Whether to include the + current timestamp in the dictionary. Defaults to False. + include_agent (bool, optional): Whether to include the agent's name + in the dictionary. Defaults to False. + agent_name (str, optional): The name of the agent when include_agent + is true. Defaults to AgentName.UNSTRACT_DBWRITER. + single_column_name (str, optional): The name of the single column + when using 'WRITE_JSON_TO_A_SINGLE_COLUMN' mode. + Defaults to "data". + + Returns: + dict: A dictionary containing columns and values based on + the specified parameters. + """ + + values: dict[str, Any] = {} + try: + column_mode = ColumnModes(column_mode_str) + except ValueError: + # Handle the case where the string is not a valid enum value + column_mode = ColumnModes.WRITE_JSON_TO_A_SINGLE_COLUMN + + if include_agent and agent_name: + values[TableColumns.CREATED_BY] = agent_name + + if include_timestamp: + values[TableColumns.CREATED_AT] = datetime.datetime.now() + + if column_mode == ColumnModes.WRITE_JSON_TO_A_SINGLE_COLUMN: + if isinstance(data, str): + values[single_column_name] = data + else: + values[single_column_name] = json.dumps(data) + if column_mode == ColumnModes.SPLIT_JSON_INTO_COLUMNS: + if isinstance(data, dict): + values.update(data) + elif isinstance(data, str): + values[single_column_name] = data + else: + values[single_column_name] = json.dumps(data) + + return values + + @staticmethod + def get_sql_values_for_query( + engine: Any, table_name: str, values: dict[str, Any] + ) -> list[str]: + """Generate SQL values for an insert query based on the provided values + and table schema. + + Args: + engine (Any): The database engine. + table_name (str): The name of the target table for the insert query. + values (dict[str, Any]): A dictionary containing column-value pairs + for the insert query. + + Returns: + list[str]: A list of SQL values suitable for use in an insert query. + + Note: + - This function determines the database type based on the + `engine` parameter. + - If the database is Snowflake (DBConnectionClass.SNOWFLAKE), + it handles Snowflake-specific SQL generation. + - For other SQL databases, it uses default SQL generation + based on column types. + """ + + if engine.__class__.__name__ == DBConnectionClass.SNOWFLAKE: + # Handle Snowflake + column_types: dict[str, str] = DatabaseUtils.get_column_types( + engine=engine, + table_name=table_name, + cls=DBConnectionClass.SNOWFLAKE, + ) + sql_values = DatabaseUtils.make_sql_values_for_query( + values=values, + column_types=column_types, + cls=DBConnectionClass.SNOWFLAKE, + ) + else: + # Default to Other SQL DBs + column_types = DatabaseUtils.get_column_types( + engine=engine, table_name=table_name + ) + sql_values = DatabaseUtils.make_sql_values_for_query( + values=values, column_types=column_types + ) + return sql_values + + @staticmethod + def execute_write_query( + engine: Any, + table_name: str, + sql_keys: list[str], + sql_values: list[str], + ) -> None: + """Execute Insert Query. + + Args: + engine (Any): _description_ + table_name (str): table name + sql_keys (list[str]): columns + sql_values (list[str]): values + Notes: + - Snowflake does not support INSERT INTO ... VALUES ... + syntax when VARIANT columns are present (JSON). + So we need to use INSERT INTO ... SELECT ... syntax + """ + sql = ( + f"INSERT INTO {table_name} ({','.join(sql_keys)}) " + f"SELECT {','.join(sql_values)}" + ) + + try: + with engine.cursor() as cursor: + cursor.execute(sql) + engine.commit() + except Exception as e: + logger.error(f"Error while writing data: {str(e)}") + raise e + + @staticmethod + def get_db_engine( + connector_id: str, connector_settings: dict[str, Any] + ) -> Any: + connector = db_connectors[connector_id][Common.METADATA][ + Common.CONNECTOR + ] + connector_class: UnstractDB = connector(connector_settings) + return connector_class.get_engine() diff --git a/backend/workflow_manager/endpoint/destination.py b/backend/workflow_manager/endpoint/destination.py new file mode 100644 index 000000000..2fb16eb03 --- /dev/null +++ b/backend/workflow_manager/endpoint/destination.py @@ -0,0 +1,430 @@ +import ast +import json +import logging +import os +from typing import Any, Optional + +import fsspec +import magic +from account.models import EncryptionSecret +from connector.models import ConnectorInstance +from cryptography.fernet import Fernet +from django.db import connection +from fsspec.implementations.local import LocalFileSystem +from unstract.sdk.constants import ToolExecKey +from unstract.workflow_execution.constants import ToolOutputType +from workflow_manager.endpoint.base_connector import BaseConnector +from workflow_manager.endpoint.constants import ( + ApiDeploymentResultStatus, + DestinationKey, + WorkflowFileType, +) +from workflow_manager.endpoint.database_utils import DatabaseUtils +from workflow_manager.endpoint.exceptions import ( + DestinationConnectorNotConfigured, + InvalidDestinationConnectionType, + InvalidToolOutputType, + MissingDestinationConnectionType, + ToolOutputTypeMismatch, +) +from workflow_manager.endpoint.models import WorkflowEndpoint +from workflow_manager.workflow.enums import ExecutionStatus +from workflow_manager.workflow.file_history_helper import FileHistoryHelper +from workflow_manager.workflow.models.file_history import FileHistory +from workflow_manager.workflow.models.workflow import Workflow + +logger = logging.getLogger(__name__) + + +class DestinationConnector(BaseConnector): + """A class representing a Destination connector for a workflow. + + This class extends the BaseConnector class and provides methods for + interacting with different types of destination connectors, + such as file system connectors and API connectors and DB connectors. + + Attributes: + workflow (Workflow): The workflow associated with + the destination connector. + """ + + def __init__(self, workflow: Workflow, execution_id: str) -> None: + """Initialize a DestinationConnector object. + + Args: + workflow (Workflow): _description_ + """ + organization_id = connection.tenant.schema_name + super().__init__(workflow.id, execution_id, organization_id) + self.endpoint = self._get_endpoint_for_workflow(workflow=workflow) + self.execution_id = execution_id + self.api_results: list[dict[str, Any]] = [] + + def _get_endpoint_for_workflow( + self, + workflow: Workflow, + ) -> WorkflowEndpoint: + """Get WorkflowEndpoint instance. + + Args: + workflow (Workflow): Workflow associated with the + destination connector. + + Returns: + WorkflowEndpoint: WorkflowEndpoint instance. + """ + endpoint: WorkflowEndpoint = WorkflowEndpoint.objects.get( + workflow=workflow, + endpoint_type=WorkflowEndpoint.EndpointType.DESTINATION, + ) + if endpoint.connector_instance: + encryption_secret: EncryptionSecret = EncryptionSecret.objects.get() + f: Fernet = Fernet(encryption_secret.key.encode("utf-8")) + endpoint.connector_instance.connector_metadata = json.loads( + f.decrypt( + bytes(endpoint.connector_instance.connector_metadata_b + ).decode( + "utf-8" + ) + ) + ) + return endpoint + + def validate(self) -> None: + connection_type = self.endpoint.connection_type + connector: ConnectorInstance = self.endpoint.connector_instance + if connection_type is None: + raise MissingDestinationConnectionType() + if connection_type not in WorkflowEndpoint.ConnectionType.values: + raise InvalidDestinationConnectionType() + if ( + connection_type != WorkflowEndpoint.ConnectionType.API + and connector is None + ): + raise DestinationConnectorNotConfigured() + + def handle_output( + self, + file_name: str, + file_hash: str, + workflow: Workflow, + file_history: Optional[FileHistory] = None, + error: Optional[str] = None, + ) -> None: + """Handle the output based on the connection type.""" + connection_type = self.endpoint.connection_type + result: Optional[str] = None + if error: + if connection_type == WorkflowEndpoint.ConnectionType.API: + self._handle_api_result( + file_name=file_name, error=error, result=result + ) + return + if connection_type == WorkflowEndpoint.ConnectionType.FILESYSTEM: + self.copy_output_to_output_directory() + elif connection_type == WorkflowEndpoint.ConnectionType.DATABASE: + self.insert_into_db(file_history) + elif connection_type == WorkflowEndpoint.ConnectionType.API: + result = self.get_result(file_history) + self._handle_api_result( + file_name=file_name, error=error, result=result + ) + if not file_history: + FileHistoryHelper.create_file_history( + cache_key=file_hash, + workflow=workflow, + status=ExecutionStatus.COMPLETED, + result=result, + ) + + def copy_output_to_output_directory(self) -> None: + """Copy output to the destination directory.""" + connector: ConnectorInstance = self.endpoint.connector_instance + connector_settings: dict[str, Any] = connector.connector_metadata + destination_configurations: dict[str, Any] = self.endpoint.configuration + root_path = str(connector_settings.get(DestinationKey.PATH)) + output_folder = str( + destination_configurations.get(DestinationKey.OUTPUT_FOLDER, "/") + ) + overwrite = bool( + destination_configurations.get( + DestinationKey.OVERWRITE_OUTPUT_DOCUMENT, False + ) + ) + output_directory = os.path.join(root_path, output_folder) + + destination_volume_path = os.path.join( + self.execution_dir, ToolExecKey.OUTPUT_DIR + ) + + connector_fs = self.get_fsspec( + settings=connector_settings, connector_id=connector.connector_id + ) + if not connector_fs.isdir(output_directory): + connector_fs.mkdir(output_directory) + + # Traverse local directory and create the same structure in the + # output_directory + for root, dirs, files in os.walk(destination_volume_path): + for dir_name in dirs: + connector_fs.mkdir( + os.path.join( + output_directory, + os.path.relpath(root, destination_volume_path), + dir_name, + ) + ) + + for file_name in files: + source_path = os.path.join(root, file_name) + destination_path = os.path.join( + output_directory, + os.path.relpath(root, destination_volume_path), + file_name, + ) + normalized_path = os.path.normpath(destination_path) + with open(source_path, "rb") as source_file: + connector_fs.write_bytes( + normalized_path, source_file.read(), overwrite=overwrite + ) + + def insert_into_db(self, file_history: Optional[FileHistory]) -> None: + """Insert data into the database.""" + connector_instance: ConnectorInstance = self.endpoint.connector_instance + connector_settings: dict[ + str, Any + ] = connector_instance.connector_metadata + destination_configurations: dict[str, Any] = self.endpoint.configuration + table_name: str = str( + destination_configurations.get(DestinationKey.TABLE) + ) + include_agent: bool = bool( + destination_configurations.get(DestinationKey.INCLUDE_AGENT, False) + ) + include_timestamp = bool( + destination_configurations.get( + DestinationKey.INCLUDE_TIMESTAMP, False + ) + ) + agent_name = str( + destination_configurations.get(DestinationKey.AGENT_NAME) + ) + column_mode = str( + destination_configurations.get(DestinationKey.COLUMN_MODE) + ) + single_column_name = str( + destination_configurations.get( + DestinationKey.SINGLE_COLUMN_NAME, "data" + ) + ) + + data = self.get_result(file_history) + + values = DatabaseUtils.get_columns_and_values( + column_mode_str=column_mode, + data=data, + include_timestamp=include_timestamp, + include_agent=include_agent, + agent_name=agent_name, + single_column_name=single_column_name, + ) + + engine = DatabaseUtils.get_db_engine( + connector_id=connector_instance.connector_id, + connector_settings=connector_settings, + ) + sql_values = DatabaseUtils.get_sql_values_for_query( + engine=engine, table_name=table_name, values=values + ) + + DatabaseUtils.execute_write_query( + engine=engine, + table_name=table_name, + sql_keys=list(values.keys()), + sql_values=sql_values, + ) + + def _handle_api_result( + self, + file_name: str, + error: Optional[str] = None, + result: Optional[str] = None, + ) -> None: + """Handle the API result. + + This method is responsible for handling the API result. + It appends the file name and result to the 'results' list for API resp. + + Args: + file_name (str): The name of the file. + result (Optional[str], optional): The result of the API call. + Defaults to None. + + Returns: + None + """ + api_result = {"file": file_name} + if error: + api_result.update( + {"status": ApiDeploymentResultStatus.FAILED, "error": error} + ) + else: + if result: + api_result.update( + { + "status": ApiDeploymentResultStatus.SUCCESS, + "result": result, + } + ) + else: + api_result.update( + {"status": ApiDeploymentResultStatus.SUCCESS, "result": ""} + ) + self.api_results.append(api_result) + + def parse_string(self, original_string: str) -> Any: + """Parse the given string, attempting to evaluate it as a Python + literal. + ex: a json string to dict method + Parameters: + - original_string (str): The input string to be parsed. + + Returns: + - Any: The parsed result. If the string can be evaluated as a Python + literal, the result of the evaluation is returned. + If not, the original string is returned unchanged. + + Note: + This function uses `ast.literal_eval` to attempt parsing the string as a + Python literal. If parsing fails due to a SyntaxError or ValueError, + the original string is returned. + + Example: + >>> parser.parse_string("42") + 42 + >>> parser.parse_string("[1, 2, 3]") + [1, 2, 3] + >>> parser.parse_string("Hello, World!") + 'Hello, World!' + """ + try: + # Try to evaluate as a Python literal + python_literal = ast.literal_eval(original_string) + return python_literal + except (SyntaxError, ValueError): + # If evaluating as a Python literal fails, + # assume it's a plain string + return original_string + + def get_result(self, file_history: Optional[FileHistory]) -> Optional[Any]: + """Get result data from the output file. + + Returns: + Union[dict[str, Any], str]: Result data. + """ + if file_history and file_history.result: + return self.parse_string(file_history.result) + + output_file = os.path.join(self.execution_dir, WorkflowFileType.INFILE) + metadata = self.get_workflow_metadata() + output_type = self.get_output_type(metadata) + result: Optional[Any] = None + try: + # TODO: SDK handles validation; consider removing here. + mime = magic.Magic() + file_type = mime.from_file(output_file) + if output_type == ToolOutputType.JSON: + if "JSON" not in file_type: + logger.error(f"Output type json mismatched {file_type}") + raise ToolOutputTypeMismatch() + with open(output_file) as file: + result = json.load(file) + elif output_type == ToolOutputType.TXT: + if "JSON" in file_type: + logger.error(f"Output type txt mismatched {file_type}") + raise ToolOutputTypeMismatch() + with open(output_file) as file: + result = file.read() + result = result.encode("utf-8").decode("unicode-escape") + else: + raise InvalidToolOutputType() + except (FileNotFoundError, json.JSONDecodeError) as err: + logger.error(f"Error while getting result {err}") + return result + + def delete_execution_directory(self) -> None: + """Delete the execution directory. + + Returns: + None + """ + fs: LocalFileSystem = fsspec.filesystem("file") + fs.rm(self.execution_dir, recursive=True) + self.delete_api_storage_dir(self.workflow_id, self.execution_id) + + @classmethod + def delete_api_storage_dir( + cls, workflow_id: str, execution_id: str + ) -> None: + """Delete the api storage path. + + Returns: + None + """ + api_storage_dir = cls.get_api_storage_dir_path( + workflow_id=workflow_id, execution_id=execution_id + ) + fs: LocalFileSystem = fsspec.filesystem("file") + fs.rm(api_storage_dir, recursive=True) + + @classmethod + def create_endpoint_for_workflow( + cls, + workflow: Workflow, + ) -> None: + """Create a workflow endpoint for the destination. + + Args: + workflow (Workflow): Workflow for which the endpoint is created. + """ + endpoint = WorkflowEndpoint( + workflow=workflow, + endpoint_type=WorkflowEndpoint.EndpointType.DESTINATION, + ) + endpoint.save() + + @classmethod + def get_json_schema_for_database(cls) -> dict[str, Any]: + """Get JSON schema for the database. + + Returns: + dict[str, Any]: JSON schema for the database. + """ + schema_path = os.path.join( + os.path.dirname(__file__), "static", "dest", "db.json" + ) + return cls.get_json_schema(file_path=schema_path) + + @classmethod + def get_json_schema_for_file_system(cls) -> dict[str, Any]: + """Get JSON schema for the file system. + + Returns: + dict[str, Any]: JSON schema for the file system. + """ + schema_path = os.path.join( + os.path.dirname(__file__), "static", "dest", "file.json" + ) + return cls.get_json_schema(file_path=schema_path) + + @classmethod + def get_json_schema_for_api(cls) -> dict[str, Any]: + """Json schema for api. + + Returns: + dict[str, Any]: _description_ + """ + schema_path = os.path.join( + os.path.dirname(__file__), "static", "dest", "api.json" + ) + return cls.get_json_schema(file_path=schema_path) diff --git a/backend/workflow_manager/endpoint/endpoint_utils.py b/backend/workflow_manager/endpoint/endpoint_utils.py new file mode 100644 index 000000000..467ddb7e6 --- /dev/null +++ b/backend/workflow_manager/endpoint/endpoint_utils.py @@ -0,0 +1,30 @@ +from workflow_manager.endpoint.destination import DestinationConnector +from workflow_manager.endpoint.models import WorkflowEndpoint +from workflow_manager.endpoint.source import SourceConnector +from workflow_manager.workflow.models.workflow import Workflow +from workflow_manager.workflow.workflow_helper import WorkflowHelper + + +class WorkflowEndpointUtils: + @staticmethod + def create_endpoints_for_workflow(workflow: Workflow) -> None: + """Create endpoints for a given workflow. This method creates both + source and destination endpoints for the specified workflow. + + Parameters: + workflow (Workflow): The workflow for which + the endpoints need to be created. + + Returns: + None + """ + SourceConnector.create_endpoint_for_workflow(workflow) + DestinationConnector.create_endpoint_for_workflow(workflow) + + @staticmethod + def get_endpoints_for_workflow(workflow_id: str) -> list[WorkflowEndpoint]: + workflow = WorkflowHelper.get_workflow_by_id(workflow_id) + endpoints: list[WorkflowEndpoint] = WorkflowEndpoint.objects.filter( + workflow=workflow + ) + return endpoints diff --git a/backend/workflow_manager/endpoint/exceptions.py b/backend/workflow_manager/endpoint/exceptions.py new file mode 100644 index 000000000..03e82ea06 --- /dev/null +++ b/backend/workflow_manager/endpoint/exceptions.py @@ -0,0 +1,63 @@ +from rest_framework.exceptions import APIException + + +class InvalidInputDirectory(APIException): + status_code = 400 + default_detail = "The provided directory is invalid." + + +class InvalidSourceConnectionType(APIException): + status_code = 400 + default_detail = "The provided source connection type is invalid." + + +class InvalidDestinationConnectionType(APIException): + status_code = 400 + default_detail = "The provided destination connection type is invalid." + + +class MissingSourceConnectionType(APIException): + status_code = 400 + default_detail = "The source connection type is missing." + + +class MissingDestinationConnectionType(APIException): + status_code = 400 + default_detail = "The destination connection type is missing." + + +class SourceConnectorNotConfigured(APIException): + status_code = 400 + default_detail = "The source connector is not configured" + + +class DestinationConnectorNotConfigured(APIException): + status_code = 400 + default_detail = "The destination connector is not configured" + + +class FileHashNotFound(APIException): + status_code = 500 + default_detail = "Internal server error: File hash not found." + + +class ToolMetadataNotFound(APIException): + status_code = 500 + default_detail = "Internal server error: Tool metadata not found." + + +class OrganizationIdNotFound(APIException): + status_code = 404 + default_detail = "The organization ID could not be found" + + +class InvalidToolOutputType(APIException): + status_code = 500 + default_detail = "Invalid output type is returned from tool" + + +class ToolOutputTypeMismatch(APIException): + status_code = 400 + default_detail = ( + "The data type of the tool's output does not match the expected type." + ) diff --git a/backend/workflow_manager/endpoint/migrations/0001_initial.py b/backend/workflow_manager/endpoint/migrations/0001_initial.py new file mode 100644 index 000000000..2f714ce6b --- /dev/null +++ b/backend/workflow_manager/endpoint/migrations/0001_initial.py @@ -0,0 +1,88 @@ +# Generated by Django 4.2.1 on 2024-01-23 11:18 + +import uuid + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + ("connector", "0001_initial"), + ("workflow", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="WorkflowEndpoint", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "endpoint_type", + models.CharField( + choices=[ + ("SOURCE", "Source connector"), + ("DESTINATION", "Destination Connector"), + ], + db_comment="Endpoint type (source or destination)", + editable=False, + ), + ), + ( + "connection_type", + models.CharField( + blank=True, + choices=[ + ("FILESYSTEM", "FileSystem connector"), + ("DATABASE", "Database Connector"), + ("API", "API Connector"), + ], + db_comment="Connection type (Filesystem, Database or API)", + ), + ), + ( + "configuration", + models.JSONField( + blank=True, + db_comment="Configuration in JSON format", + null=True, + ), + ), + ( + "connector_instance", + models.ForeignKey( + db_comment="Foreign key from ConnectorInstance model", + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="connector.connectorinstance", + ), + ), + ( + "workflow", + models.ForeignKey( + db_comment="Foreign key from Workflow model", + editable=False, + on_delete=django.db.models.deletion.CASCADE, + to="workflow.workflow", + ), + ), + ], + options={ + "verbose_name": "Workflow Endpoint", + "verbose_name_plural": "Workflow Endpoints", + "db_table": "workflow_endpoints", + }, + ), + ] diff --git a/backend/workflow_manager/endpoint/migrations/__init__.py b/backend/workflow_manager/endpoint/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/workflow_manager/endpoint/models.py b/backend/workflow_manager/endpoint/models.py new file mode 100644 index 000000000..a90c583ac --- /dev/null +++ b/backend/workflow_manager/endpoint/models.py @@ -0,0 +1,51 @@ +import uuid + +from connector.models import ConnectorInstance +from django.db import models +from utils.models.base_model import BaseModel +from workflow_manager.workflow.models.workflow import Workflow + + +class WorkflowEndpoint(BaseModel): + class EndpointType(models.TextChoices): + SOURCE = "SOURCE", "Source connector" + DESTINATION = "DESTINATION", "Destination Connector" + + class ConnectionType(models.TextChoices): + FILESYSTEM = "FILESYSTEM", "FileSystem connector" + DATABASE = "DATABASE", "Database Connector" + API = "API", "API Connector" + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + workflow = models.ForeignKey( + Workflow, + on_delete=models.CASCADE, + db_index=True, + editable=False, + db_comment="Foreign key from Workflow model", + ) + endpoint_type = models.CharField( + choices=EndpointType.choices, + editable=False, + db_comment="Endpoint type (source or destination)", + ) + connection_type = models.CharField( + choices=ConnectionType.choices, + blank=True, + db_comment="Connection type (Filesystem, Database or API)", + ) + configuration = models.JSONField( + blank=True, null=True, db_comment="Configuration in JSON format" + ) + connector_instance = models.ForeignKey( + ConnectorInstance, + on_delete=models.CASCADE, + db_index=True, + null=True, + db_comment="Foreign key from ConnectorInstance model", + ) + + class Meta: + db_table = "workflow_endpoints" + verbose_name = "Workflow Endpoint" + verbose_name_plural = "Workflow Endpoints" diff --git a/backend/workflow_manager/endpoint/serializers.py b/backend/workflow_manager/endpoint/serializers.py new file mode 100644 index 000000000..30ce2f890 --- /dev/null +++ b/backend/workflow_manager/endpoint/serializers.py @@ -0,0 +1,12 @@ +import logging + +from rest_framework.serializers import ModelSerializer +from workflow_manager.endpoint.models import WorkflowEndpoint + +logger = logging.getLogger(__name__) + + +class WorkflowEndpointSerializer(ModelSerializer): + class Meta: + model = WorkflowEndpoint + fields = "__all__" diff --git a/backend/workflow_manager/endpoint/source.py b/backend/workflow_manager/endpoint/source.py new file mode 100644 index 000000000..7e9e3fd03 --- /dev/null +++ b/backend/workflow_manager/endpoint/source.py @@ -0,0 +1,482 @@ +import fnmatch +import json +import logging +import os +import shutil +from hashlib import md5, sha256 +from pathlib import Path +from typing import Any, Optional + +import fsspec +from account.models import EncryptionSecret +from connector.models import ConnectorInstance +from connector_processor.constants import ConnectorKeys +from cryptography.fernet import Fernet +from django.core.files.uploadedfile import UploadedFile +from django.db import connection +from unstract.workflow_execution.enums import LogState +from workflow_manager.endpoint.base_connector import BaseConnector +from workflow_manager.endpoint.constants import ( + FilePattern, + FileSystemConnector, + FileType, + SourceConstant, + SourceKey, + WorkflowFileType, +) +from workflow_manager.endpoint.exceptions import ( + FileHashNotFound, + InvalidInputDirectory, + InvalidSourceConnectionType, + MissingSourceConnectionType, + OrganizationIdNotFound, + SourceConnectorNotConfigured, +) +from workflow_manager.endpoint.models import WorkflowEndpoint +from workflow_manager.workflow.execution import WorkflowExecutionServiceHelper +from workflow_manager.workflow.models.workflow import Workflow + +logger = logging.getLogger(__name__) + + +class SourceConnector(BaseConnector): + """A class representing a source connector for a workflow. + + This class extends the BaseConnector class and provides methods for + interacting with different types of source connectors, + such as file system connectors and API connectors. + It allows listing files from the source connector, + adding files to the execution volume, and retrieving JSON schemas for + different types of connectors. + + Attributes: + workflow (Workflow): The workflow associated with the source connector. + """ + + def __init__( + self, + workflow: Workflow, + execution_id: str, + organization_id: Optional[str] = None, + execution_service: Optional[WorkflowExecutionServiceHelper] = None, + ) -> None: + """Initialize a SourceConnector object. + + Args: + workflow (Workflow): _description_ + """ + organization_id = organization_id or connection.tenant.schema_name + if not organization_id: + raise OrganizationIdNotFound() + super().__init__(workflow.id, execution_id, organization_id) + self.endpoint = self._get_endpoint_for_workflow(workflow=workflow) + self.workflow = workflow + self.execution_id = execution_id + self.organization_id = organization_id + self.hash_value_of_file_content: Optional[str] = None + self.execution_service = execution_service + + def _get_endpoint_for_workflow( + self, + workflow: Workflow, + ) -> WorkflowEndpoint: + """Get WorkflowEndpoint instance. + + Args: + workflow (Workflow): Workflow + + Returns: + WorkflowEndpoint: _description_ + """ + endpoint: WorkflowEndpoint = WorkflowEndpoint.objects.get( + workflow=workflow, + endpoint_type=WorkflowEndpoint.EndpointType.SOURCE, + ) + if endpoint.connector_instance: + encryption_secret: EncryptionSecret = EncryptionSecret.objects.get() + f: Fernet = Fernet(encryption_secret.key.encode("utf-8")) + endpoint.connector_instance.connector_metadata = json.loads( + f.decrypt( + bytes(endpoint.connector_instance.connector_metadata_b + ).decode( + "utf-8" + ) + ) + ) + + return endpoint + + def validate(self) -> None: + connection_type = self.endpoint.connection_type + connector: ConnectorInstance = self.endpoint.connector_instance + if connection_type is None: + raise MissingSourceConnectionType() + if connection_type not in WorkflowEndpoint.ConnectionType.values: + raise InvalidSourceConnectionType() + if ( + connection_type != WorkflowEndpoint.ConnectionType.API + and connector is None + ): + raise SourceConnectorNotConfigured() + + def valid_file_patterns(self, required_patterns: list[Any]) -> list[str]: + patterns = { + FileType.PDF_DOCUMENTS: FilePattern.PDF_DOCUMENTS, + FileType.TEXT_DOCUMENTS: FilePattern.TEXT_DOCUMENTS, + FileType.WORD_DOCUMENTS: FilePattern.WORD_DOCUMENTS, + FileType.OPENOFFICE_DOCUMENTS: FilePattern.OPENOFFICE_DOCUMENTS, + FileType.IMAGES: FilePattern.IMAGES, + } + wildcard = [] + if not required_patterns: + wildcard.append("*") + else: + for pattern in required_patterns: + wildcard.extend(patterns.get(pattern, [])) + return wildcard + + def list_file_from_api_storage(self) -> list[str]: + """List all files from the api_storage_dir directory.""" + files: list[str] = [] + if not self.api_storage_dir: + return files + for file in os.listdir(self.api_storage_dir): + file_path = os.path.join(self.api_storage_dir, file) + if os.path.isfile(file_path): + files.append(file_path) + return files + + def list_files_from_file_connector(self) -> list[str]: + """_summary_ + + Raises: + InvalidDirectory: _description_ + + Returns: + list[str]: _description_ + """ + connector: ConnectorInstance = self.endpoint.connector_instance + connector_settings: dict[str, Any] = connector.connector_metadata + source_configurations: dict[str, Any] = self.endpoint.configuration + required_patterns = source_configurations.get( + SourceKey.FILE_EXTENSIONS, [] + ) + recursive = bool( + source_configurations.get(SourceKey.PROCESS_SUB_DIRECTORIES, False) + ) + limit = int( + source_configurations.get( + SourceKey.MAX_FILES, FileSystemConnector.MAX_FILES + ) + ) + root_dir_path = connector_settings.get(ConnectorKeys.PATH, "") + input_directory = str( + source_configurations.get(SourceKey.ROOT_FOLDER, "") + ) + input_directory = str(Path(root_dir_path, input_directory.lstrip("/"))) + if not isinstance(required_patterns, list): + required_patterns = [required_patterns] + + source_fs = self.get_fsspec( + settings=connector_settings, connector_id=connector.connector_id + ) + patterns = self.valid_file_patterns(required_patterns=required_patterns) + is_directory = source_fs.isdir(input_directory) + if not is_directory: + raise InvalidInputDirectory() + matched_files = self._get_matched_files( + source_fs, input_directory, patterns, recursive, limit + ) + self.publish_input_output_list_file_logs(input_directory, matched_files) + return matched_files + + def publish_input_output_list_file_logs( + self, input_directory: str, matched_files: list[str] + ) -> None: + if not self.execution_service: + return None + input_log = ( + f"##Input folder:\n\n `{os.path.basename(input_directory)}`\n\n" + ) + self.execution_service.publish_update_log( + state=LogState.INPUT_UPDATE, message=input_log + ) + output_log = self._matched_files_component_log(matched_files) + self.execution_service.publish_update_log( + state=LogState.OUTPUT_UPDATE, message=output_log + ) + + def publish_input_file_content( + self, input_file_path: str, input_text: str + ) -> None: + if self.execution_service: + output_log_message = ( + f"##Input text:\n\n```text\n{input_text}\n```\n\n" + ) + input_log_message = ( + "##Input file:\n\n```text\n" + f"{os.path.basename(input_file_path)}\n```\n\n" + ) + self.execution_service.publish_update_log( + state=LogState.INPUT_UPDATE, message=input_log_message + ) + self.execution_service.publish_update_log( + state=LogState.OUTPUT_UPDATE, message=output_log_message + ) + + def _matched_files_component_log(self, matched_files: list[str]) -> str: + output_log = "### Matched files \n```text\n\n\n" + for file in matched_files[:20]: + output_log += f"{file}\n" + output_log += "```\n\n" + output_log += f"""Total matched files: {len(matched_files)} + \n\nPlease note that only the first 20 files are shown.\n\n""" + return output_log + + def _get_matched_files( + self, + source_fs: Any, + input_directory: str, + patterns: list[str], + recursive: bool, + limit: int, + ) -> list[str]: + """Get a list of matched files based on patterns in a directory. + + This method searches for files in the specified `input_directory` that + match any of the given `patterns`. + The search can be performed recursively if `recursive` is set to True. + The number of matched files returned is limited by `limit`. + + Args: + source_fs (Any): The file system object used for searching. + input_directory (str): The directory to search for files. + patterns (list[str]): The patterns to match against file names. + recursive (bool): Whether to perform a recursive search. + limit (int): The maximum number of matched files to return. + + Returns: + list[str]: A list of matched file paths. + """ + matched_files = [] + count = 0 + max_depth = int(SourceConstant.MAX_RECURSIVE_DEPTH) if recursive else 1 + + for root, dirs, files in source_fs.walk( + input_directory, maxdepth=max_depth + ): + if count >= limit: + break + for file in files: + if not file: + continue + if count >= limit: + break + if any(fnmatch.fnmatch(file, pattern) for pattern in patterns): + file_path = os.path.join(root, file) + file_path = f"{file_path}" + matched_files.append(file_path) + count += 1 + + return matched_files + + def list_files_from_source(self) -> list[str]: + """List files from source connector. + + Args: + api_storage_dir (Optional[str], optional): API storage directory + Returns: + list[str]: list of files + """ + connection_type = self.endpoint.connection_type + if connection_type == WorkflowEndpoint.ConnectionType.FILESYSTEM: + return self.list_files_from_file_connector() + elif connection_type == WorkflowEndpoint.ConnectionType.API: + return self.list_file_from_api_storage() + raise InvalidSourceConnectionType() + + @classmethod + def hash_str(cls, string_to_hash: Any, hash_method: str = "sha256") -> str: + """Computes the hash for a given input string. + + Useful to hash strings needed for caching and other purposes. + Hash method defaults to "md5" + + Args: + string_to_hash (str): String to be hashed + hash_method (str): Hash hash_method to use, supported ones + - "md5" + + Returns: + str: Hashed string + """ + if hash_method == "md5": + if isinstance(string_to_hash, bytes): + return str(md5(string_to_hash).hexdigest()) + return str(md5(string_to_hash.encode()).hexdigest()) + elif hash_method == "sha256": + if isinstance(string_to_hash, (bytes, bytearray)): + return str(sha256(string_to_hash).hexdigest()) + return str(sha256(string_to_hash.encode()).hexdigest()) + else: + raise ValueError(f"Unsupported hash_method: {hash_method}") + + def add_input_from_connector_to_volume(self, input_file_path: str) -> str: + """Add input file to execution directory. + + Args: + input_file_path (str): The path of the input file. + Returns: + str: The hash value of the file content. + Raises: + FileHashNotFound: If the hash value of the file content + is not found. + """ + connector: ConnectorInstance = self.endpoint.connector_instance + connector_settings: dict[str, Any] = connector.connector_metadata + source_file_path = os.path.join( + self.execution_dir, WorkflowFileType.SOURCE + ) + infile_path = os.path.join(self.execution_dir, WorkflowFileType.INFILE) + source_file = f"file://{source_file_path}" + + source_fs = self.get_fsspec( + settings=connector_settings, connector_id=connector.connector_id + ) + with ( + source_fs.open(input_file_path, "rb") as remote_file, + fsspec.open(source_file, "wb") as local_file, + ): + file_content = remote_file.read() + hash_value_of_file_content = self.hash_str(file_content) + logger.info( + f"hash_value_of_file {source_file} is " + f": {hash_value_of_file_content}" + ) + input_log = ( + file_content[:500].decode("utf-8", errors="replace") + + "...(truncated)" + ) + self.publish_input_file_content(input_file_path, input_log) + + local_file.write(file_content) + shutil.copyfile(source_file_path, infile_path) + logger.info(f"{input_file_path} is added in to execution directory") + return hash_value_of_file_content + + def add_input_from_api_storage_to_volume( + self, input_file_path: str + ) -> None: + """Add input file to execution directory from api storage.""" + infile_path = os.path.join(self.execution_dir, WorkflowFileType.INFILE) + source_path = os.path.join(self.execution_dir, WorkflowFileType.SOURCE) + shutil.copyfile(input_file_path, infile_path) + shutil.copyfile(input_file_path, source_path) + + def add_file_to_volume( + self, input_file_path: str, hash_values_of_files: dict[str, str] = {} + ) -> tuple[str, str]: + """Add input file to execution directory. + + Args: + input_file_path (str): source file + + Raises: + InvalidSource: _description_ + + Returns: + str: file_name + """ + connection_type = self.endpoint.connection_type + file_name = os.path.basename(input_file_path) + if connection_type == WorkflowEndpoint.ConnectionType.FILESYSTEM: + file_content_hash = self.add_input_from_connector_to_volume( + input_file_path=input_file_path, + ) + elif connection_type == WorkflowEndpoint.ConnectionType.API: + self.add_input_from_api_storage_to_volume( + input_file_path=input_file_path + ) + if file_name not in hash_values_of_files: + raise FileHashNotFound() + file_content_hash = hash_values_of_files[file_name] + else: + raise InvalidSourceConnectionType() + + self.add_metadata_to_volume( + input_file_path=input_file_path, source_hash=file_content_hash + ) + return file_name, file_content_hash + + def handle_final_result( + self, + results: list[dict[str, Any]], + file_name: str, + result: Optional[str], + ) -> None: + connection_type = self.endpoint.connection_type + if connection_type == WorkflowEndpoint.ConnectionType.API: + results.append({"file": file_name, "result": result}) + + @classmethod + def add_input_file_to_api_storage( + cls, workflow_id: str, execution_id: str, file_objs: list[UploadedFile] + ) -> dict[str, str]: + """Add input file to api storage. + + Args: + workflow_id (str): workflow id + execution_id (str): execution_id + file_objs (list[UploadedFile]): api file objects + """ + api_storage_dir = cls.get_api_storage_dir_path( + workflow_id=workflow_id, execution_id=execution_id + ) + file_hashes: dict[str, str] = {} + for file in file_objs: + file_name = file.name + destination_path = os.path.join(api_storage_dir, file_name) + os.makedirs(os.path.dirname(destination_path), exist_ok=True) + with open(destination_path, "wb") as f: + buffer = bytearray() + for chunk in file.chunks(): + buffer.extend(chunk) + f.write(buffer) + file_hashes.update({file_name: cls.hash_str(buffer)}) + return file_hashes + + @classmethod + def create_endpoint_for_workflow( + cls, + workflow: Workflow, + ) -> None: + """Creating WorkflowEndpoint entity.""" + endpoint = WorkflowEndpoint( + workflow=workflow, + endpoint_type=WorkflowEndpoint.EndpointType.SOURCE, + ) + endpoint.save() + + @classmethod + def get_json_schema_for_api(cls) -> dict[str, Any]: + """Json schema for api. + + Returns: + dict[str, Any]: _description_ + """ + schema_path = os.path.join( + os.path.dirname(__file__), "static", "src", "api.json" + ) + return cls.get_json_schema(file_path=schema_path) + + @classmethod + def get_json_schema_for_file_system(cls) -> dict[str, Any]: + """Json schema for Filesystem. + + Returns: + dict[str, Any]: _description_ + """ + schema_path = os.path.join( + os.path.dirname(__file__), "static", "src", "file.json" + ) + return cls.get_json_schema(file_path=schema_path) diff --git a/backend/workflow_manager/endpoint/static/dest/db.json b/backend/workflow_manager/endpoint/static/dest/db.json new file mode 100644 index 000000000..fea9028bb --- /dev/null +++ b/backend/workflow_manager/endpoint/static/dest/db.json @@ -0,0 +1,55 @@ +{ + "title": "Workflow DB Destination", + "description": "Settings for DB Destination", + "type": "object", + "required": [ + "table", + "includeAgent", + "includeTimestamp", + "columnMode" + ], + "properties": { + "table": { + "type": "string", + "title": "Table", + "default": "", + "description": "Table to store the output. If your database supports schemas, use the format schema.table" + }, + "includeAgent": { + "type": "boolean", + "title": "Include 'created_by' column", + "default": false, + "description": "Include the 'created_by' in the output row" + }, + "agentName": { + "type": "string", + "title": "Agent Name", + "enum": [ + "Unstract/DBWriter" + ], + "default": "Unstract/DBWriter", + "description": "Name of the agent to use as the 'created_by' value" + }, + "includeTimestamp": { + "type": "boolean", + "title": "Include 'created_at' column", + "default": false, + "description": "Include the 'created_at' in the output row" + }, + "columnMode": { + "type": "string", + "title": "Select how you want to write the output", + "enum": [ + "Split JSON into columns", + "Write JSON to a single column" + ], + "default": "Split JSON into columns" + }, + "singleColumnName": { + "type": "string", + "title": "Single Column Name", + "default": "data", + "description": "Name of the column to write the JSON to" + } + } +} diff --git a/backend/workflow_manager/endpoint/static/dest/file.json b/backend/workflow_manager/endpoint/static/dest/file.json new file mode 100644 index 000000000..aa3a1263e --- /dev/null +++ b/backend/workflow_manager/endpoint/static/dest/file.json @@ -0,0 +1,25 @@ +{ + "title": "Workflow File Destination", + "description": "Settings for File Destination", + "type": "object", + "required": [ + "outputFolder" + ], + "properties": { + "outputFolder": { + "type": "string", + "title": "Output folder", + "default": "output", + "description": "Folder to store the output", + "minLength": 1, + "maxLength": 100, + "format": "file-path" + }, + "overwriteOutput": { + "type": "boolean", + "title": "Overwrite existing output", + "default": true, + "description": "Used to overwrite output document" + } + } +} diff --git a/backend/workflow_manager/endpoint/static/src/api.json b/backend/workflow_manager/endpoint/static/src/api.json new file mode 100644 index 000000000..b3d2ca1c2 --- /dev/null +++ b/backend/workflow_manager/endpoint/static/src/api.json @@ -0,0 +1,23 @@ +{ + "title": "Workflow API Source", + "description": "Settings for API Source", + "type": "object", + "required": [], + "properties": { + "fileExtensions": { + "type": "array", + "title": "File types to process", + "description": "Limit the file types to process. Leave it empty to process all files", + "items": { + "type": "string", + "enum": [ + "PDF documents", + "Text documents", + "Word documents", + "Openoffice documents", + "Images" + ] + } + } + } +} diff --git a/backend/workflow_manager/endpoint/static/src/file.json b/backend/workflow_manager/endpoint/static/src/file.json new file mode 100644 index 000000000..ef5c22219 --- /dev/null +++ b/backend/workflow_manager/endpoint/static/src/file.json @@ -0,0 +1,41 @@ +{ + "title": "Workflow File Source", + "description": "Settings for File Source", + "type": "object", + "required": [], + "properties": { + "rootFolder": { + "type": "string", + "title": "Folder to process", + "default": "", + "description": "The root folder to start processing files from. Leave it empty to use the root folder" + }, + "processSubDirectories": { + "type": "boolean", + "title": "Process sub directories", + "default": true, + "description": "Process sub directories recursively" + }, + "fileExtensions": { + "type": "array", + "title": "File types to process", + "description": "Limit the file types to process. Leave it empty to process all files", + "items": { + "type": "string", + "enum": [ + "PDF documents", + "Text documents", + "Word documents", + "Openoffice documents", + "Images" + ] + } + }, + "maxFiles": { + "type": "number", + "title": "Max files to process", + "default": 100, + "description": "The maximum number of files to process" + } + } +} diff --git a/backend/workflow_manager/endpoint/tests.py b/backend/workflow_manager/endpoint/tests.py new file mode 100644 index 000000000..a39b155ac --- /dev/null +++ b/backend/workflow_manager/endpoint/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/backend/workflow_manager/endpoint/urls.py b/backend/workflow_manager/endpoint/urls.py new file mode 100644 index 000000000..9efd62f80 --- /dev/null +++ b/backend/workflow_manager/endpoint/urls.py @@ -0,0 +1,25 @@ +from django.urls import path +from workflow_manager.endpoint.views import WorkflowEndpointViewSet + +workflow_endpoint_list = WorkflowEndpointViewSet.as_view( + {"get": "workflow_endpoint_list"} +) +endpoint_list = WorkflowEndpointViewSet.as_view({"get": "list"}) +workflow_endpoint_detail = WorkflowEndpointViewSet.as_view( + {"get": "retrieve", "put": "update"} +) +endpoint_settings_detail = WorkflowEndpointViewSet.as_view( + {"get": WorkflowEndpointViewSet.get_settings.__name__} +) + +urlpatterns = [ + path("", endpoint_list, name="endpoint-list"), + path( + "/", workflow_endpoint_detail, name="workflow-endpoint-detail" + ), + path( + "/settings/", + endpoint_settings_detail, + name="workflow-endpoint-detail", + ), +] diff --git a/backend/workflow_manager/endpoint/views.py b/backend/workflow_manager/endpoint/views.py new file mode 100644 index 000000000..b84c6f9b3 --- /dev/null +++ b/backend/workflow_manager/endpoint/views.py @@ -0,0 +1,86 @@ +from django.db.models import QuerySet +from rest_framework import status, viewsets +from rest_framework.decorators import action +from rest_framework.request import Request +from rest_framework.response import Response +from workflow_manager.endpoint.destination import DestinationConnector +from workflow_manager.endpoint.endpoint_utils import WorkflowEndpointUtils +from workflow_manager.endpoint.models import WorkflowEndpoint +from workflow_manager.endpoint.source import SourceConnector +from workflow_manager.workflow.serializers import WorkflowEndpointSerializer + + +class WorkflowEndpointViewSet(viewsets.ModelViewSet): + queryset = WorkflowEndpoint.objects.all() + serializer_class = WorkflowEndpointSerializer + + def get_queryset(self) -> QuerySet: + + queryset = ( + WorkflowEndpoint.objects.all() + .select_related("workflow") + .filter(workflow__created_by=self.request.user) + ) + endpoint_type_filter = self.request.query_params.get( + "endpoint_type", None + ) + connection_type_filter = self.request.query_params.get( + "connection_type", None + ) + if endpoint_type_filter: + queryset = queryset.filter(endpoint_type=endpoint_type_filter) + if connection_type_filter: + queryset = queryset.filter(connection_type=connection_type_filter) + return queryset + + @action(detail=True, methods=["get"]) + def get_settings(self, request: Request, pk: str) -> Response: + """Retrieve the settings/schema for a specific workflow endpoint. + + Parameters: + request (Request): The HTTP request object. + pk (str): The primary key of the workflow endpoint. + + Returns: + Response: The HTTP response containing the settings/schema for + the endpoint. + """ + endpoint: WorkflowEndpoint = self.get_object() + connection_type = endpoint.connection_type + endpoint_type = endpoint.endpoint_type + schema = None + if endpoint_type == WorkflowEndpoint.EndpointType.SOURCE: + if connection_type == WorkflowEndpoint.ConnectionType.API: + schema = SourceConnector.get_json_schema_for_api() + if connection_type == WorkflowEndpoint.ConnectionType.FILESYSTEM: + schema = SourceConnector.get_json_schema_for_file_system() + if endpoint_type == WorkflowEndpoint.EndpointType.DESTINATION: + if connection_type == WorkflowEndpoint.ConnectionType.DATABASE: + schema = DestinationConnector.get_json_schema_for_database() + if connection_type == WorkflowEndpoint.ConnectionType.FILESYSTEM: + schema = DestinationConnector.get_json_schema_for_file_system() + if connection_type == WorkflowEndpoint.ConnectionType.API: + schema = DestinationConnector.get_json_schema_for_api() + + return Response( + { + "status": status.HTTP_200_OK, + "schema": schema, + } + ) + + @action(detail=True, methods=["get"]) + def workflow_endpoint_list(self, request: Request, pk: str) -> Response: + """Retrieve a list of endpoints for a specific workflow. + + Parameters: + request (Request): The HTTP request object. + pk (str): The primary key of the workflow. + + Returns: + Response: The HTTP response containing the serialized list of + endpoints. + """ + endpoints = WorkflowEndpointUtils.get_endpoints_for_workflow(pk) + serializer = WorkflowEndpointSerializer(endpoints, many=True) + return Response(serializer.data) diff --git a/backend/workflow_manager/urls.py b/backend/workflow_manager/urls.py new file mode 100644 index 000000000..aa5aebd36 --- /dev/null +++ b/backend/workflow_manager/urls.py @@ -0,0 +1,20 @@ +from django.urls import include, path +from workflow_manager.endpoint import urls as endpoint_urls +from workflow_manager.workflow import urls as workflow_urls + +urlpatterns = [ + path("endpoint/", include(endpoint_urls)), + path( + "/endpoint/", + include( + [ + path( + "", + endpoint_urls.workflow_endpoint_list, + name="workflow-endpoint", + ) + ] + ), + ), + path("", include(workflow_urls)), +] diff --git a/backend/workflow_manager/workflow/__init__.py b/backend/workflow_manager/workflow/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/workflow_manager/workflow/admin.py b/backend/workflow_manager/workflow/admin.py new file mode 100644 index 000000000..705599e49 --- /dev/null +++ b/backend/workflow_manager/workflow/admin.py @@ -0,0 +1,4 @@ +from django.contrib import admin +from workflow_manager.workflow.models.workflow import Workflow + +admin.site.register(Workflow) diff --git a/backend/workflow_manager/workflow/apps.py b/backend/workflow_manager/workflow/apps.py new file mode 100644 index 000000000..71e894363 --- /dev/null +++ b/backend/workflow_manager/workflow/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class WorkflowConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "workflow_manager.workflow" diff --git a/backend/workflow_manager/workflow/constants.py b/backend/workflow_manager/workflow/constants.py new file mode 100644 index 000000000..95aab13e3 --- /dev/null +++ b/backend/workflow_manager/workflow/constants.py @@ -0,0 +1,60 @@ +class WorkflowKey: + """Dict keys related to workflows.""" + + PROMPT_TEXT = "prompt_text" + LLM_RESPONSE = "llm_response" + WF_STEPS = "steps" + WF_TOOL = "tool" + WF_INSTANCE_SETTINGS = "instance_settings" + WF_TOOL_INSTANCE_ID = "tool_instance_id" + WF_CONNECTOR_CLASS = "connector_class" + WF_INPUT = "input" + WF_OUTPUT = "output" + WF_TOOL_UUID = "id" + WF_ID = "workflow_id" + WF_NAME = "workflow_name" + WF_OWNER = "workflow_owner" + WF_TOOL_INSTANCES = "tool_instances" + WF_IS_ACTIVE = "is_active" + EXECUTION_ACTION = "execution_action" + # Keys from provisional workflow + PWF_RESULT = "result" + PWF_OUTPUT = "output" + PWF_COST_TYPE = "cost_type" + PWF_COST = "cost" + PWF_TIME_TAKEN = "time_taken" + WF_CACHE_PATTERN = r"^cache:{?\w{8}-?\w{4}-?\w{4}-?\w{4}-?\w{12}}?$" + WF_PROJECT_GUID = "guid" + + +class WorkflowExecutionKey: + WORKFLOW_EXECUTION_ID_PREFIX = "workflow" + EXECUTION_ID = "execution_id" + LOG_GUID = "log_guid" + WITH_LOG = "with_log" + + +class WorkflowErrors: + WORKFLOW_EXISTS = "Workflow with this configuration already exists." + DUPLICATE_API = "It appears that a duplicate call may have been made." + INVALID_EXECUTION_ID = "Invalid execution_id" + + +class CeleryConfigurations: + INTERVAL = 2 + + +class Tool: + APIOPS = "apiops" + + +class WorkflowMessages: + CACHE_CLEAR_SUCCESS = "Cache cleared successfully." + CACHE_CLEAR_FAILED = "Failed to clear cache." + CACHE_EMPTY = "Cache is already empty." + CELERY_TIMEOUT_MESSAGE = ( + "Your request is being processed. Please wait." + "You can check the status using the status API." + ) + FILE_MARKER_CLEAR_SUCCESS = "File marker cleared successfully." + FILE_MARKER_CLEAR_FAILED = "Failed to clear file marker." diff --git a/backend/workflow_manager/workflow/dto.py b/backend/workflow_manager/workflow/dto.py new file mode 100644 index 000000000..1f16d7df3 --- /dev/null +++ b/backend/workflow_manager/workflow/dto.py @@ -0,0 +1,68 @@ +from dataclasses import dataclass +from typing import Any, Optional + +from celery.result import AsyncResult +from workflow_manager.workflow.constants import WorkflowKey + + +@dataclass +class ProvisionalWorkflow: + result: str + output: dict[str, str] + cost_type: str + cost: str + time_taken: float + + def __init__(self, input_dict: dict[str, Any]) -> None: + self.result = input_dict.get(WorkflowKey.PWF_RESULT, "") + self.output = input_dict.get(WorkflowKey.PWF_OUTPUT, {}) + self.cost_type = input_dict.get(WorkflowKey.PWF_COST_TYPE, "") + self.cost = input_dict.get(WorkflowKey.PWF_COST, "") + self.time_taken = input_dict.get(WorkflowKey.PWF_TIME_TAKEN, 0.0) + + +@dataclass +class ExecutionResponse: + workflow_id: str + execution_id: str + execution_status: str + log_id: Optional[str] = None + status_api: Optional[str] = None + error: Optional[str] = None + mode: Optional[str] = None + result: Optional[Any] = None + message: Optional[str] = None + + def __post_init__(self) -> None: + self.log_id = self.log_id or None + self.mode = self.mode or None + self.error = self.error or None + self.result = self.result or None + self.message = self.message or None + self.status_api = self.status_api or None + + +@dataclass +class AsyncResultData: + id: str + status: str + result: Any + is_ready: bool + is_failed: bool + info: Any + + def __init__(self, async_result: AsyncResult): + self.id = async_result.id + self.status = async_result.status + self.result = async_result.result + self.is_ready = async_result.ready() + self.is_failed = async_result.failed() + self.info = async_result.info + if isinstance(self.result, Exception): + self.result = str(self.result) + + def to_dict(self) -> dict[str, Any]: + return { + "status": self.status, + "result": self.result, + } diff --git a/backend/workflow_manager/workflow/enums.py b/backend/workflow_manager/workflow/enums.py new file mode 100644 index 000000000..cc13a1e35 --- /dev/null +++ b/backend/workflow_manager/workflow/enums.py @@ -0,0 +1,73 @@ +from enum import Enum + +from utils.common_utils import ModelEnum + + +class WorkflowExecutionMethod(Enum): + INSTANT = "INSTANT" + QUEUED = "QUEUED" + + +class ExecutionStatus(ModelEnum): + """An enumeration representing the various statuses of an execution + process. + + Statuses: + PENDING: The execution's entry has been created in the database. + QUEUED: The execution task is queued for asynchronous execution + INITIATED: The execution has been initiated. + READY: The execution is ready for the build phase. + EXECUTING: The execution is currently in progress. + COMPLETED: The execution has been successfully completed. + STOPPED: The execution was stopped by the user + (applicable to step executions). + ERROR: An error occurred during the execution process. + + Note: + Intermediate statuses might not be experienced due to + Django's query triggering once all processes are completed. + """ + + PENDING = "PENDING" + INITIATED = "INITIATED" + QUEUED = "QUEUED" + READY = "READY" + EXECUTING = "EXECUTING" + COMPLETED = "COMPLETED" + STOPPED = "STOPPED" + ERROR = "ERROR" + + +class SchemaType(Enum): + """Possible types for workflow module's JSON schema. + + Values: + src: Refers to the source module's schema + dest: Refers to the destination module's schema + """ + + SRC = "src" + DEST = "dest" + + +class SchemaEntity(Enum): + """Possible entities for workflow module's JSON schema. + + Values: + file: Refers to schema for file based sources + api: Refers to schema for API based sources + db: Refers to schema for DB based destinations + """ + + FILE = "file" + API = "api" + DB = "db" + + +class ColumnModes(Enum): + WRITE_JSON_TO_A_SINGLE_COLUMN = "Write JSON to a single column" + SPLIT_JSON_INTO_COLUMNS = "Split JSON into columns" + + +class AgentName(Enum): + UNSTRACT_DBWRITER = "Unstract/DBWriter" diff --git a/backend/workflow_manager/workflow/exceptions.py b/backend/workflow_manager/workflow/exceptions.py new file mode 100644 index 000000000..82a9b3538 --- /dev/null +++ b/backend/workflow_manager/workflow/exceptions.py @@ -0,0 +1,67 @@ +from typing import Optional + +from rest_framework.exceptions import APIException + + +class WorkflowGenerationError(APIException): + status_code = 500 + default_detail = "Error generating workflow." + + +class WorkflowRegenerationError(APIException): + status_code = 500 + default_detail = "Error regenerating workflow." + + +class WorkflowExecutionError(APIException): + status_code = 400 + default_detail = "Error executing workflow." + + +class WorkflowDoesNotExistError(APIException): + status_code = 404 + default_detail = "Workflow does not exist" + + +class TaskDoesNotExistError(APIException): + status_code = 404 + default_detail = "Task does not exist" + + +class DuplicateActionError(APIException): + status_code = 400 + default_detail = "Action is running" + + +class InvalidRequest(APIException): + status_code = 400 + default_detail = "Invalid Request" + + +class InternalException(APIException): + """Internal Error. + + Args: + APIException (_type_): _description_ + """ + + status_code = 500 + + +class WorkflowExecutionNotExist(APIException): + status_code = 404 + default_detail = "Workflow execution does not exist" + + +class WorkflowExecutionBadRequestException(APIException): + status_code = 400 + default_detail = "Bad request" + + def __init__( + self, detail: Optional[str] = None, code: Optional[int] = None + ): + if detail is not None: + self.detail = detail + if code is not None: + self.code = code + super().__init__(detail, code) diff --git a/backend/workflow_manager/workflow/execution.py b/backend/workflow_manager/workflow/execution.py new file mode 100644 index 000000000..59388d860 --- /dev/null +++ b/backend/workflow_manager/workflow/execution.py @@ -0,0 +1,455 @@ +import logging +import time +import uuid +from typing import Optional + +from api.exceptions import InvalidAPIRequest +from django.db import connection +from platform_settings.platform_auth_service import ( + PlatformAuthenticationService, +) +from tool_instance.constants import JsonSchemaKey +from tool_instance.models import ToolInstance +from tool_instance.tool_processor import ToolProcessor +from unstract.tool_registry.dto import Tool +from unstract.workflow_execution import WorkflowExecutionService +from unstract.workflow_execution.dto import ( + ToolInstance as ToolInstanceDataClass, +) +from unstract.workflow_execution.dto import WorkflowDto +from unstract.workflow_execution.enums import ( + ExecutionType, + LogComponent, + LogState, +) +from unstract.workflow_execution.exceptions import StopExecution +from workflow_manager.workflow.constants import WorkflowKey +from workflow_manager.workflow.enums import ExecutionStatus +from workflow_manager.workflow.exceptions import WorkflowExecutionError +from workflow_manager.workflow.models import Workflow, WorkflowExecution +from workflow_manager.workflow.models.execution import EXECUTION_ERROR_LENGTH +from workflow_manager.workflow.models.file_history import FileHistory + +logger = logging.getLogger(__name__) + + +class WorkflowExecutionServiceHelper(WorkflowExecutionService): + def __init__( + self, + workflow: Workflow, + tool_instances: list[ToolInstance], + organization_id: Optional[str] = None, + pipeline_id: Optional[str] = None, + single_step: bool = False, + scheduled: bool = False, + mode: tuple[str, str] = WorkflowExecution.Mode.INSTANT, + workflow_execution: Optional[WorkflowExecution] = None, + ) -> None: + tool_instances_as_dto = [] + for tool_instance in tool_instances: + tool_instances_as_dto.append( + self.convert_tool_instance_model_to_data_class(tool_instance) + ) + workflow_as_dto: WorkflowDto = ( + self.convert_workflow_model_to_data_class(workflow=workflow) + ) + organization_id = organization_id or connection.tenant.schema_name + if not organization_id: + raise WorkflowExecutionError(detail="invalid Organization ID") + + platform_key = PlatformAuthenticationService.get_active_platform_key() + super().__init__( + organization_id=organization_id, + workflow_id=workflow.id, + workflow=workflow_as_dto, + tool_instances=tool_instances_as_dto, + platform_service_api_key=str(platform_key.key), + ignore_processed_entities=False, + ) + if not workflow_execution: + self.execution_log_id = uuid.uuid4() + self.execution_mode = mode + self.execution_method: tuple[str, str] = ( + WorkflowExecution.Method.SCHEDULED + if scheduled + else WorkflowExecution.Method.DIRECT + ) + self.execution_type: tuple[str, str] = ( + WorkflowExecution.Type.STEP + if single_step + else WorkflowExecution.Type.COMPLETE + ) + workflow_execution = WorkflowExecution( + pipeline_id=pipeline_id, + workflow_id=workflow.id, + execution_mode=mode, + execution_method=self.execution_method, + execution_type=self.execution_type, + status=ExecutionStatus.INITIATED.value, + # TODO: Review use of this + project_settings_id=self.execution_log_id, + ) + workflow_execution.save() + else: + self.execution_mode = workflow_execution.execution_mode + self.execution_method = workflow_execution.execution_method + self.execution_type = workflow_execution.execution_type + self.execution_log_id = workflow_execution.project_settings_id + + self.set_messaging_channel(str(self.execution_log_id)) + project_settings = {} + project_settings[WorkflowKey.WF_PROJECT_GUID] = str( + self.execution_log_id + ) + self.workflow_id = workflow.id + self.project_settings = project_settings + self.pipeline_id = pipeline_id + self.execution_id = str(workflow_execution.id) + + self.compilation_result = self.compile_workflow( + execution_id=self.execution_id + ) + + def _initiate_api_execution( + self, tool_instance: ToolInstance, execution_path: Optional[str] + ) -> None: + if not execution_path: + raise InvalidAPIRequest("File shouldn't be empty") + tool_instance.metadata[JsonSchemaKey.ROOT_FOLDER] = execution_path + + @staticmethod + def create_workflow_execution( + workflow_id: str, + pipeline_id: Optional[str] = None, + single_step: bool = False, + scheduled: bool = False, + log_guid: Optional[str] = None, + execution_id: Optional[str] = None, + mode: tuple[str, str] = WorkflowExecution.Mode.INSTANT, + ) -> WorkflowExecution: + execution_method: tuple[str, str] = ( + WorkflowExecution.Method.SCHEDULED + if scheduled + else WorkflowExecution.Method.DIRECT + ) + execution_type: tuple[str, str] = ( + WorkflowExecution.Type.STEP + if single_step + else WorkflowExecution.Type.COMPLETE + ) + execution_log_id = uuid.uuid4() if not log_guid else log_guid + workflow_execution = WorkflowExecution( + pipeline_id=pipeline_id, + workflow_id=workflow_id, + execution_mode=mode, + execution_method=execution_method, + execution_type=execution_type, + status=ExecutionStatus.PENDING.value, + project_settings_id=execution_log_id, + ) + if execution_id: + workflow_execution.id = execution_id + workflow_execution.save() + return workflow_execution + + def __update_execution( + self, + status: Optional[ExecutionStatus] = None, + execution_time: Optional[float] = None, + error: Optional[str] = None, + increment_attempt: bool = False, + ) -> None: + execution = WorkflowExecution.objects.get(pk=self.execution_id) + + if status is not None: + execution.status = status.value + if execution_time is not None: + execution.execution_time = execution_time + if error: + execution.error_message = error + if increment_attempt: + execution.attempts += 1 + + execution.save() + + def __execution_error( + self, + error_message: str, + detailed_message: str, + execution_time: Optional[float] = None, + ) -> WorkflowExecutionError: + self.__update_execution( + status=ExecutionStatus.ERROR, + error=detailed_message, + execution_time=execution_time, + ) + return WorkflowExecutionError(detail=error_message) + + def has_successful_compilation(self) -> bool: + return self.compilation_result["success"] is True + + def get_execution_instance(self) -> WorkflowExecution: + execution: WorkflowExecution = WorkflowExecution.objects.get( + pk=self.execution_id + ) + return execution + + def build(self) -> None: + if self.compilation_result["success"] is True: + self.build_workflow() + self.__update_execution(status=ExecutionStatus.READY) + else: + logger.error( + "Errors while compiling workflow " + f"{self.compilation_result['problems']}" + ) + raise self.__execution_error( + error_message=self.compilation_result["problems"][0], + detailed_message=self.compilation_result["problems"][0], + ) + + def execute(self, single_step: bool = False) -> None: + execution_type = ExecutionType.COMPLETE + if single_step: + execution_type = ExecutionType.STEP + + if self.compilation_result["success"] is True: + self.__update_execution(status=ExecutionStatus.READY) + if ( + self.execution_mode == WorkflowExecution.Mode.INSTANT + or self.execution_mode == WorkflowExecution.Mode.QUEUE + ): + start_time = time.time() + try: + self.__update_execution(increment_attempt=True) + self.execute_workflow(execution_type=execution_type) + end_time = time.time() + execution_time = end_time - start_time + self.__update_execution( + status=ExecutionStatus.COMPLETED, + execution_time=execution_time, + ) + except StopExecution as exception: + end_time = time.time() + execution_time = end_time - start_time + self.__update_execution( + status=ExecutionStatus.STOPPED, + error=str(exception), + execution_time=execution_time, + ) + logger.info(f"Execution {self.execution_id} stopped") + raise exception + except Exception as exception: + end_time = time.time() + execution_time = end_time - start_time + message = str(exception)[:EXECUTION_ERROR_LENGTH] + logger.info( + f"Execution {self.execution_id} Error {exception}" + ) + raise self.__execution_error( + error_message=message, + detailed_message=message, + execution_time=execution_time, + ) + else: + error_message = ( + f"Unknown Execution Method {self.execution_mode}" + ) + raise self.__execution_error( + error_message=error_message, detailed_message=error_message + ) + + else: + error_message = f"Errors while compiling workflow {self.compilation_result['problems'][0]}" # noqa + raise self.__execution_error( + error_message=error_message, detailed_message=error_message + ) + + def publish_initial_workflow_logs(self, total_files: int) -> None: + """Publishes the initial logs for the workflow. + + Args: + total_files (int): The total number of matched files. + + Returns: + None + """ + self.publish_log(f"Total matched files: {total_files}") + self.publish_update_log( + LogState.BEGIN_WORKFLOW, "1", LogComponent.STATUS_BAR + ) + self.publish_update_log( + LogState.RUNNING, "Ready for execution", LogComponent.WORKFLOW + ) + + def publish_final_workflow_logs(self) -> None: + """Publishes the final logs for the workflow. + + Returns: + None + """ + self.publish_update_log( + LogState.END_WORKFLOW, "1", LogComponent.STATUS_BAR + ) + self.publish_update_log( + LogState.SUCCESS, "Executed successfully", LogComponent.WORKFLOW + ) + + def publish_initial_tool_execution_logs( + self, current_step: int, total_step: int, file_name: str + ) -> None: + """Publishes the initial logs for tool execution. + + Args: + current_step (int): The current step number. + total_step (int): The total number of steps. + file_name (str): The name of the file being processed. + + Returns: + None + """ + self.publish_update_log( + component=LogComponent.STATUS_BAR, + state=LogState.MESSAGE, + message=f"Processing file {current_step}/{total_step}", + ) + self.publish_log(f"Processing file {file_name}") + + def execute_input_file( + self, + file_name: str, + single_step: bool, + file_history: Optional[FileHistory] = None, + ) -> None: + """Executes the input file. + + Args: + file_name (str): The name of the file to be executed. + single_step (bool): Flag indicating whether to execute in + single step mode. + file_history (Optional[FileHistory], optional): + The file history object. Defaults to None. + + Returns: + None + """ + execution_type = ExecutionType.COMPLETE + if single_step: + execution_type = ExecutionType.STEP + if not (file_history and file_history.is_completed()): + self.execute_uncached_input( + file_name=file_name, single_step=single_step + ) + else: + self.publish_log( + f"Skipping file {file_name} as it is already processed." + "Clear the cache to process it again" + ) + self.publish_log(f"Tool executed successfully for {file_name}") + self._handle_execution_type(execution_type) + + def execute_uncached_input(self, file_name: str, single_step: bool) -> None: + """Executes the uncached input file. + + Args: + file_name (str): The name of the file to be executed. + single_step (bool): Flag indicating whether to execute in + single step mode. + + Returns: + None + """ + self.publish_log("No entries found in cache, executing the tools") + self.publish_update_log( + state=LogState.SUCCESS, + message=f"{file_name} Sent for execution", + component=LogComponent.SOURCE, + ) + self.execute(single_step) + + def initiate_tool_execution( + self, + current_step: int, + total_step: int, + file_name: str, + single_step: bool, + ) -> None: + """Initiates the execution of a tool for a specific file in the + workflow. + + Args: + current_step (int): The current step number in the workflow. + total_step (int): The total number of steps in the workflow. + file_name (str): The name of the file being processed. + single_step (bool): Flag indicating whether the execution is in + single-step mode. + + Returns: + None + + Raises: + None + """ + execution_type = ExecutionType.COMPLETE + if single_step: + execution_type = ExecutionType.STEP + self.publish_initial_tool_execution_logs( + current_step, total_step, file_name + ) + self._handle_execution_type(execution_type) + + source_status_message = ( + f"({current_step}/{total_step})Processing file {file_name}" + ) + self.publish_update_log( + state=LogState.RUNNING, + message=source_status_message, + component=LogComponent.SOURCE, + ) + self.publish_log("Trying to fetch results from cache") + + @staticmethod + def update_execution_status( + execution_id: str, status: ExecutionStatus + ) -> None: + try: + execution = WorkflowExecution.objects.get(pk=execution_id) + execution.status = status.value + execution.save() + except WorkflowExecution.DoesNotExist: + logger.error(f"execution doesn't exist {execution_id}") + + @staticmethod + def update_execution_task(execution_id: str, task_id: str) -> None: + try: + execution = WorkflowExecution.objects.get(pk=execution_id) + execution.task_id = task_id + execution.save() + except WorkflowExecution.DoesNotExist: + logger.error(f"execution doesn't exist {execution_id}") + + @staticmethod + def convert_tool_instance_model_to_data_class( + tool_instance: ToolInstance, + ) -> ToolInstanceDataClass: + tool: Tool = ToolProcessor.get_tool_by_uid(tool_instance.tool_id) + tool_dto = ToolInstanceDataClass( + id=tool_instance.id, + tool_id=tool_instance.tool_id, + workflow=tool_instance.workflow.id, + metadata=tool_instance.metadata, + step=tool_instance.step, + properties=tool.properties, + image_name=tool.image_name, + image_tag=tool.image_tag, + ) + return tool_dto + + @staticmethod + def convert_workflow_model_to_data_class( + workflow: Workflow, + ) -> WorkflowDto: + return WorkflowDto( + id=workflow.id, + settings=workflow.settings, + ) diff --git a/backend/workflow_manager/workflow/file_history_helper.py b/backend/workflow_manager/workflow/file_history_helper.py new file mode 100644 index 000000000..b49bd3507 --- /dev/null +++ b/backend/workflow_manager/workflow/file_history_helper.py @@ -0,0 +1,70 @@ +from typing import Any, Optional + +from workflow_manager.workflow.enums import ExecutionStatus +from workflow_manager.workflow.models.file_history import FileHistory +from workflow_manager.workflow.models.workflow import Workflow + + +class FileHistoryHelper: + """A helper class for managing file history related operations.""" + + @staticmethod + def get_file_history( + workflow: Workflow, cache_key: Optional[str] = None + ) -> Optional[FileHistory]: + """Retrieve a file history record based on the cache key. + + Args: + cache_key (Optional[str]): The cache key to search for. + + Returns: + Optional[FileHistory]: The matching file history record, if found. + """ + if not cache_key: + return None + try: + file_history: FileHistory = FileHistory.objects.get( + cache_key=cache_key, workflow=workflow + ) + except FileHistory.DoesNotExist: + return None + return file_history + + @staticmethod + def create_file_history( + cache_key: str, + workflow: Workflow, + status: ExecutionStatus, + result: Any, + error: Optional[str] = None, + ) -> FileHistory: + """Create a new file history record. + + Args: + cache_key (str): The cache key for the file. + workflow (Workflow): The associated workflow. + status (ExecutionStatus): The execution status. + result (Any): The result from the execution. + + Returns: + FileHistory: The newly created file history record. + """ + file_history: FileHistory = FileHistory.objects.create( + workflow=workflow, + cache_key=cache_key, + status=status.value, + result=str(result), + error=str(error) if error else "", + ) + return file_history + + @staticmethod + def clear_history_for_workflow( + workflow: Workflow, + ) -> None: + """Clear all file history records associated with a workflow. + + Args: + workflow (Workflow): The workflow to clear the history for. + """ + FileHistory.objects.filter(workflow=workflow).delete() diff --git a/backend/workflow_manager/workflow/generator.py b/backend/workflow_manager/workflow/generator.py new file mode 100644 index 000000000..f611cb2fc --- /dev/null +++ b/backend/workflow_manager/workflow/generator.py @@ -0,0 +1,118 @@ +import logging +import uuid +from typing import Any + +from rest_framework.request import Request +from tool_instance.constants import ToolInstanceKey as TIKey +from tool_instance.exceptions import ToolInstantiationError +from tool_instance.tool_processor import ToolProcessor +from unstract.core.llm_workflow_generator.llm_interface import LLMInterface +from unstract.tool_registry.dto import Tool +from workflow_manager.workflow.constants import WorkflowKey +from workflow_manager.workflow.dto import ProvisionalWorkflow +from workflow_manager.workflow.exceptions import WorkflowGenerationError +from workflow_manager.workflow.models.workflow import Workflow as WorkflowModel + +logger = logging.getLogger(__name__) + + +class WorkflowGenerator: + """Helps with generating a workflow using the LLM.""" + + def __init__(self, workflow_id: str = str(uuid.uuid4())) -> None: + self._request: Request = {} + self._llm_response = "" + self._workflow_id = workflow_id + self._provisional_wf: ProvisionalWorkflow + + @property + def llm_response(self) -> dict[str, Any]: + output: dict[str, str] = self._provisional_wf.output + return output + + @property + def provisional_wf(self) -> ProvisionalWorkflow: + return self._provisional_wf + + def _get_provisional_workflow( + self, tools: list[Tool] + ) -> ProvisionalWorkflow: + """Helper to generate the provisional workflow Gets stored as + `workflow.Workflow.llm_response` eventually.""" + provisional_wf: ProvisionalWorkflow + try: + if not self._request: + raise WorkflowGenerationError( + "Unable to generate a workflow: missing request" + ) + llm_interface = LLMInterface() + + provisional_wf_dict = ( + llm_interface.get_provisional_workflow_from_llm( + workflow_id=self._workflow_id, + tools=tools, + user_prompt=self._request.data.get(WorkflowKey.PROMPT_TEXT), + use_cache=True, + ) + ) + provisional_wf = ProvisionalWorkflow(provisional_wf_dict) + if provisional_wf.result != "OK": + raise WorkflowGenerationError( + f"Unable to generate a workflow: {provisional_wf.output}" + ) + except Exception as e: + logger.error(f"{e}") + raise WorkflowGenerationError + return provisional_wf + + def set_request(self, request: Request) -> None: + self._request = request + + def generate_workflow(self, tools: list[Tool]) -> None: + """Used to talk to the GPT model through core and obtain a + provisional workflow for the user to work with.""" + self._provisional_wf = self._get_provisional_workflow(tools) + + @staticmethod + def get_tool_instance_data_from_llm( + workflow: WorkflowModel, + ) -> list[dict[str, str]]: + """Used to generate the dict of tool instances for a given workflow. + + Call with ToolInstanceSerializer(data=tool_instance_data_list,many=True) + """ + tool_instance_data_list = [] + for step, tool_step in enumerate( + workflow.llm_response.get(WorkflowKey.WF_STEPS, []) + ): + step = step + 1 + logger.info(f"Building tool instance data for step: {step}") + tool_function: str = tool_step[WorkflowKey.WF_TOOL] + wf_input: str = tool_step[WorkflowKey.WF_INPUT] + wf_output: str = tool_step[WorkflowKey.WF_OUTPUT] + try: + tool: Tool = ToolProcessor.get_tool_by_uid(tool_function) + # TODO: Mark optional fields in model and handle in ToolInstance serializer # noqa + tool_instance_data = { + TIKey.PK: tool_step[WorkflowKey.WF_TOOL_UUID], + TIKey.WORKFLOW: workflow.id, + # Added to support changes for UN-154 + WorkflowKey.WF_ID: workflow.id, + TIKey.TOOL_ID: tool_function, + TIKey.METADATA: { + WorkflowKey.WF_TOOL_INSTANCE_ID: tool_step[ + WorkflowKey.WF_TOOL_UUID + ], + **ToolProcessor.get_default_settings(tool), + }, + TIKey.STEP: str(step), + TIKey.INPUT: wf_input, + TIKey.OUTPUT: wf_output, + } + tool_instance_data_list.append(tool_instance_data) + except Exception as e: + logger.error( + f"Error while getting data for {tool_function}: {e}" + ) + raise ToolInstantiationError(tool_name=tool_function) + return tool_instance_data_list diff --git a/backend/workflow_manager/workflow/migrations/0001_initial.py b/backend/workflow_manager/workflow/migrations/0001_initial.py new file mode 100644 index 000000000..9b5e2a4d2 --- /dev/null +++ b/backend/workflow_manager/workflow/migrations/0001_initial.py @@ -0,0 +1,287 @@ +# Generated by Django 4.2.1 on 2024-01-23 11:18 + +import uuid + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("project", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="WorkflowExecution", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "pipeline_id", + models.UUIDField( + db_comment="ID of the associated pipeline, if applicable", + editable=False, + null=True, + ), + ), + ( + "task_id", + models.UUIDField( + db_comment="task id of asynchronous execution", + editable=False, + null=True, + ), + ), + ( + "workflow_id", + models.UUIDField( + db_comment="Id of workflow to be executed", + editable=False, + ), + ), + ( + "project_settings_id", + models.UUIDField( + db_comment="Id of project settings used while execution", + editable=False, + ), + ), + ( + "execution_mode", + models.CharField( + choices=[ + ("INSTANT", "will be executed immediately"), + ("QUEUE", "will be placed in a queue"), + ], + db_comment="Mode of execution", + ), + ), + ( + "execution_method", + models.CharField( + choices=[ + ("DIRECT", " Execution triggered manually"), + ("SCHEDULED", "Scheduled execution"), + ], + db_comment="Method of execution", + ), + ), + ( + "execution_type", + models.CharField( + choices=[ + ("COMPLETE", "For complete execution"), + ("STEP", "For step-by-step execution "), + ], + db_comment="Type of execution", + ), + ), + ( + "status", + models.CharField( + db_comment="Current status of execution", default="" + ), + ), + ( + "error_message", + models.CharField( + blank=True, + db_comment="Details of encountered errors", + default="", + max_length=256, + ), + ), + ( + "attempts", + models.IntegerField( + db_comment="number of attempts taken", default=0 + ), + ), + ( + "execution_time", + models.FloatField( + db_comment="execution time in seconds", default=0 + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="Workflow", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ("prompt_name", models.CharField(default="", max_length=32)), + ("description", models.TextField(default="", max_length=490)), + ( + "workflow_name", + models.CharField(max_length=128, unique=True), + ), + ( + "settings", + models.JSONField(db_comment="Workflow settings", null=True), + ), + ("prompt_text", models.TextField(default="")), + ("is_active", models.BooleanField(default=False)), + ("status", models.CharField(default="", max_length=16)), + ("llm_response", models.TextField()), + ( + "deployment_type", + models.CharField( + choices=[ + ("DEFAULT", "Not ready yet"), + ("ETL", "ETL pipeline"), + ("TASK", "TASK pipeline"), + ("API", "API deployment"), + ("APP", "App deployment"), + ], + db_comment="Type of workflow deployment", + default="DEFAULT", + ), + ), + ( + "source_settings", + models.JSONField( + db_comment="Settings for the Source module", null=True + ), + ), + ( + "destination_settings", + models.JSONField( + db_comment="Settings for the Destination module", + null=True, + ), + ), + ( + "created_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="created_workflow", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "modified_by", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="modified_workflow", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "project", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="project_workflow", + to="project.project", + ), + ), + ( + "workflow_owner", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="workflow_owner", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="FileHistory", + fields=[ + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + "cache_key", + models.CharField( + db_comment="Hash value of file contents, WF and tool modified times", + max_length=64, + ), + ), + ( + "status", + models.TextField( + choices=[ + ("PENDING", "PENDING"), + ("INITIATED", "INITIATED"), + ("QUEUED", "QUEUED"), + ("READY", "READY"), + ("EXECUTING", "EXECUTING"), + ("COMPLETED", "COMPLETED"), + ("STOPPED", "STOPPED"), + ("ERROR", "ERROR"), + ], + db_comment="Latest status of execution", + ), + ), + ( + "error", + models.TextField( + blank=True, db_comment="Error message", default="" + ), + ), + ( + "result", + models.TextField( + blank=True, db_comment="Result from execution" + ), + ), + ( + "workflow", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="filehistory_workflow", + to="workflow.workflow", + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/backend/workflow_manager/workflow/migrations/__init__.py b/backend/workflow_manager/workflow/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/workflow_manager/workflow/models/__init__.py b/backend/workflow_manager/workflow/models/__init__.py new file mode 100644 index 000000000..57b3df1a1 --- /dev/null +++ b/backend/workflow_manager/workflow/models/__init__.py @@ -0,0 +1,3 @@ +from .execution import WorkflowExecution # noqa: F401 +from .file_history import FileHistory # noqa: F401 +from .workflow import Workflow # noqa: F401 diff --git a/backend/workflow_manager/workflow/models/execution.py b/backend/workflow_manager/workflow/models/execution.py new file mode 100644 index 000000000..992b91b44 --- /dev/null +++ b/backend/workflow_manager/workflow/models/execution.py @@ -0,0 +1,64 @@ +import uuid + +from django.db import models +from utils.models.base_model import BaseModel + +EXECUTION_ERROR_LENGTH = 256 + + +class WorkflowExecution(BaseModel): + class Mode(models.TextChoices): + INSTANT = "INSTANT", "will be executed immediately" + QUEUE = "QUEUE", "will be placed in a queue" + + class Method(models.TextChoices): + DIRECT = "DIRECT", " Execution triggered manually" + SCHEDULED = "SCHEDULED", "Scheduled execution" + + class Type(models.TextChoices): + COMPLETE = "COMPLETE", "For complete execution" + STEP = "STEP", "For step-by-step execution " + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + # TODO: Make as foreign key to access the instance directly + pipeline_id = models.UUIDField( + editable=False, + null=True, + db_comment="ID of the associated pipeline, if applicable", + ) + task_id = models.UUIDField( + editable=False, + null=True, + db_comment="task id of asynchronous execution", + ) + # We can remove workflow_id if it not required + workflow_id = models.UUIDField( + editable=False, db_comment="Id of workflow to be executed" + ) + project_settings_id = models.UUIDField( + editable=False, db_comment="Id of project settings used while execution" + ) + execution_mode = models.CharField( + choices=Mode.choices, db_comment="Mode of execution" + ) + execution_method = models.CharField( + choices=Method.choices, db_comment="Method of execution" + ) + execution_type = models.CharField( + choices=Type.choices, db_comment="Type of execution" + ) + status = models.CharField( + default="", db_comment="Current status of execution" + ) + error_message = models.CharField( + max_length=EXECUTION_ERROR_LENGTH, + blank=True, + default="", + db_comment="Details of encountered errors", + ) + attempts = models.IntegerField( + default=0, db_comment="number of attempts taken" + ) + execution_time = models.FloatField( + default=0, db_comment="execution time in seconds" + ) diff --git a/backend/workflow_manager/workflow/models/file_history.py b/backend/workflow_manager/workflow/models/file_history.py new file mode 100644 index 000000000..f518d2ba9 --- /dev/null +++ b/backend/workflow_manager/workflow/models/file_history.py @@ -0,0 +1,42 @@ +import uuid + +from django.db import models +from utils.models.base_model import BaseModel +from workflow_manager.workflow.enums import ExecutionStatus +from workflow_manager.workflow.models.workflow import Workflow + +HASH_LENGTH = 64 + + +class FileHistory(BaseModel): + def is_completed(self) -> bool: + """Check if the execution status is completed. + + Returns: + bool: True if the execution status is completed, False otherwise. + """ + return ( + self.status is not None + and self.status == ExecutionStatus.COMPLETED.value + ) + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + cache_key = models.CharField( + max_length=HASH_LENGTH, + db_comment="Hash value of file contents, WF and tool modified times", + ) + workflow = models.ForeignKey( + Workflow, + on_delete=models.CASCADE, + related_name="filehistory_workflow", + ) + status = models.TextField( + choices=ExecutionStatus.choices(), + db_comment="Latest status of execution", + ) + error = models.TextField( + blank=True, + default="", + db_comment="Error message", + ) + result = models.TextField(blank=True, db_comment="Result from execution") diff --git a/backend/workflow_manager/workflow/models/workflow.py b/backend/workflow_manager/workflow/models/workflow.py new file mode 100644 index 000000000..5fdfac678 --- /dev/null +++ b/backend/workflow_manager/workflow/models/workflow.py @@ -0,0 +1,84 @@ +import uuid + +from account.models import User +from django.db import models +from project.models import Project +from utils.models.base_model import BaseModel + +PROMPT_NAME_LENGTH = 32 +WORKFLOW_STATUS_LENGTH = 16 +EXECUTION_ERROR_LENGTH = 256 +DESCRIPTION_FIELD_LENGTH = 490 +WORKFLOW_NAME_SIZE = 128 + + +class Workflow(BaseModel): + class WorkflowType(models.TextChoices): + DEFAULT = "DEFAULT", "Not ready yet" + ETL = "ETL", "ETL pipeline" + TASK = "TASK", "TASK pipeline" + API = "API", "API deployment" + APP = "APP", "App deployment" + + class ExecutionAction(models.TextChoices): + START = "START", "Start the Execution" + NEXT = "NEXT", "Execute next tool" + STOP = "STOP", "Stop the execution" + CONTINUE = "CONTINUE", "Continue to full execution" + + # TODO Make this guid as primaryId instaed of current id bigint + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + project = models.ForeignKey( + Project, + on_delete=models.CASCADE, + related_name="project_workflow", + null=True, + blank=True, + ) + # TODO: Move prompt fields as a One-One relationship/into Prompt instead + prompt_name = models.CharField(max_length=PROMPT_NAME_LENGTH, default="") + description = models.TextField( + max_length=DESCRIPTION_FIELD_LENGTH, default="" + ) + workflow_name = models.CharField(max_length=WORKFLOW_NAME_SIZE, unique=True) + settings = models.JSONField(null=True, db_comment="Workflow settings") + prompt_text = models.TextField(default="") + is_active = models.BooleanField(default=False) + status = models.CharField(max_length=WORKFLOW_STATUS_LENGTH, default="") + llm_response = models.TextField() + workflow_owner = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="workflow_owner", + null=True, + blank=True, + ) + deployment_type = models.CharField( + choices=WorkflowType.choices, + db_comment="Type of workflow deployment", + default=WorkflowType.DEFAULT, + ) + source_settings = models.JSONField( + null=True, db_comment="Settings for the Source module" + ) + destination_settings = models.JSONField( + null=True, db_comment="Settings for the Destination module" + ) + + created_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="created_workflow", + null=True, + blank=True, + ) + modified_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + related_name="modified_workflow", + null=True, + blank=True, + ) + + def __str__(self) -> str: + return f"{self.id}, name: {self.workflow_name}" diff --git a/backend/workflow_manager/workflow/serializers.py b/backend/workflow_manager/workflow/serializers.py new file mode 100644 index 000000000..8efbdeca3 --- /dev/null +++ b/backend/workflow_manager/workflow/serializers.py @@ -0,0 +1,149 @@ +import logging +from typing import Any, Optional, Union + +from backend.constants import RequestKey +from backend.serializers import AuditSerializer +from project.constants import ProjectKey +from rest_framework.serializers import ( + CharField, + ChoiceField, + JSONField, + ModelSerializer, + Serializer, + UUIDField, + ValidationError, +) +from tool_instance.serializers import ToolInstanceSerializer +from tool_instance.tool_instance_helper import ToolInstanceHelper +from workflow_manager.endpoint.models import WorkflowEndpoint +from workflow_manager.workflow.constants import WorkflowExecutionKey, WorkflowKey +from workflow_manager.workflow.exceptions import WorkflowGenerationError +from workflow_manager.workflow.generator import WorkflowGenerator +from workflow_manager.workflow.models.workflow import Workflow + +logger = logging.getLogger(__name__) + + +class WorkflowSerializer(AuditSerializer): + tool_instances = ToolInstanceSerializer(many=True, read_only=True) + + class Meta: + model = Workflow + fields = "__all__" + extra_kwargs = { + WorkflowKey.LLM_RESPONSE: { + "required": False, + }, + } + + def to_representation(self, instance: Workflow) -> dict[str, str]: + representation: dict[str, str] = super().to_representation(instance) + representation[WorkflowKey.WF_NAME] = instance.workflow_name + representation[WorkflowKey.WF_TOOL_INSTANCES] = ToolInstanceSerializer( + ToolInstanceHelper.get_tool_instances_by_workflow( + workflow_id=instance.id, order_by="step" + ), + many=True, + context=self.context, + ).data + return representation + + def create(self, validated_data: dict[str, Any]) -> Any: + if self.context.get(RequestKey.REQUEST): + validated_data[WorkflowKey.WF_OWNER] = self.context.get( + RequestKey.REQUEST + ).user + return super().create(validated_data) + + def update(self, instance: Any, validated_data: dict[str, Any]) -> Any: + if validated_data.get(WorkflowKey.PROMPT_TEXT): + instance.workflow_tool.all().delete() + return super().update(instance, validated_data) + + def save(self, **kwargs: Any) -> Workflow: + workflow: Workflow = super().save(**kwargs) + if self.validated_data.get(WorkflowKey.PROMPT_TEXT): + try: + tool_serializer = ToolInstanceSerializer( + data=WorkflowGenerator.get_tool_instance_data_from_llm( + workflow=workflow + ), + many=True, + context=self.context, + ) + tool_serializer.is_valid(raise_exception=True) + tool_serializer.save() + except Exception as exc: + logger.error(f"Error while generating tool instances: {exc}") + raise WorkflowGenerationError + + request = self.context.get("request") + if not request: + return workflow + return workflow + + +class ExecuteWorkflowSerializer(Serializer): + workflow_id = UUIDField(required=False) + project_id = UUIDField(required=False) + execution_action = ChoiceField( + choices=Workflow.ExecutionAction.choices, required=False + ) + execution_id = UUIDField(required=False) + log_guid = UUIDField(required=False) + # TODO: Add other fields to handle WFExecution method, mode .etc. + + def get_workflow_id( + self, validated_data: dict[str, Union[str, None]] + ) -> Optional[str]: + return validated_data.get(WorkflowKey.WF_ID) + + def get_project_id( + self, validated_data: dict[str, Union[str, None]] + ) -> Optional[str]: + return validated_data.get(ProjectKey.PROJECT_ID) + + def get_execution_id( + self, validated_data: dict[str, Union[str, None]] + ) -> Optional[str]: + return validated_data.get(WorkflowExecutionKey.EXECUTION_ID) + + def get_log_guid( + self, validated_data: dict[str, Union[str, None]] + ) -> Optional[str]: + return validated_data.get(WorkflowExecutionKey.LOG_GUID) + + def get_execution_action( + self, validated_data: dict[str, Union[str, None]] + ) -> Optional[str]: + return validated_data.get(WorkflowKey.EXECUTION_ACTION) + + def validate( + self, data: dict[str, Union[str, None]] + ) -> dict[str, Union[str, None]]: + workflow_id = data.get(WorkflowKey.WF_ID) + project_id = data.get(ProjectKey.PROJECT_ID) + + if not workflow_id and not project_id: + raise ValidationError( + "At least one of 'workflow_id' or 'project_id' is required." + ) + + return data + + +class ExecuteWorkflowResponseSerializer(Serializer): + workflow_id = UUIDField() + execution_id = UUIDField() + execution_status = CharField() + log_id = CharField() + error = CharField() + result = JSONField() + + +class WorkflowEndpointSerializer(ModelSerializer): + workflow_name = CharField(source="workflow.workflow_name", read_only=True) + + class Meta: + model = WorkflowEndpoint + fields = "__all__" diff --git a/backend/workflow_manager/workflow/tests.py b/backend/workflow_manager/workflow/tests.py new file mode 100644 index 000000000..a39b155ac --- /dev/null +++ b/backend/workflow_manager/workflow/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/backend/workflow_manager/workflow/urls.py b/backend/workflow_manager/workflow/urls.py new file mode 100644 index 000000000..4bcc4b69c --- /dev/null +++ b/backend/workflow_manager/workflow/urls.py @@ -0,0 +1,76 @@ +from django.urls import path +from rest_framework.urlpatterns import format_suffix_patterns +from workflow_manager.workflow.views import WorkflowViewSet + +workflow_list = WorkflowViewSet.as_view( + { + "get": "list", + "post": "create", + } +) +workflow_detail = WorkflowViewSet.as_view( + # fmt: off + { + 'get': 'retrieve', + 'put': 'update', + 'patch': 'partial_update', + 'delete': 'destroy' + } + # fmt: on +) +workflow_execute = WorkflowViewSet.as_view( + {"post": "execute", "put": "activate"} +) +execution_entity = WorkflowViewSet.as_view({"get": "get_execution"}) +workflow_clear_cache = WorkflowViewSet.as_view({"get": "clear_cache"}) +workflow_clear_file_marker = WorkflowViewSet.as_view( + {"get": "clear_file_marker"} +) +workflow_schema = WorkflowViewSet.as_view({"get": "get_schema"}) +workflow_settings = WorkflowViewSet.as_view( + {"get": "workflow_settings", "put": "workflow_settings"} +) +workflow_settings_schema = WorkflowViewSet.as_view( + {"get": "workflow_settings_schema"} +) + +urlpatterns = format_suffix_patterns( + [ + path("", workflow_list, name="workflow-list"), + path("/", workflow_detail, name="workflow-detail"), + path( + "/clear-cache/", + workflow_clear_cache, + name="clear-cache", + ), + path( + "/clear-file-marker/", + workflow_clear_file_marker, + name="clear-file-marker", + ), + path("execute/", workflow_execute, name="execute-workflow"), + path( + "active//", + workflow_execute, + name="active-workflow", + ), + path( + "execution//", + execution_entity, + name="workflow-detail", + ), + path( + "schema/", + workflow_schema, + name="workflow-schema", + ), + path( + "/settings/", workflow_settings, name="workflow-settings" + ), + path( + "settings/", + workflow_settings_schema, + name="workflow-settings-schema", + ), + ] +) diff --git a/backend/workflow_manager/workflow/views.py b/backend/workflow_manager/workflow/views.py new file mode 100644 index 000000000..496c97212 --- /dev/null +++ b/backend/workflow_manager/workflow/views.py @@ -0,0 +1,372 @@ +import logging +from typing import Any, Optional + +from backend.constants import RequestKey +from connector.connector_instance_helper import ConnectorInstanceHelper +from django.conf import settings +from django.db.models.query import QuerySet +from django.http import HttpRequest +from permissions.permission import IsOwner +from pipeline.models import Pipeline +from pipeline.pipeline_processor import PipelineProcessor +from rest_framework import serializers, status, viewsets +from rest_framework.decorators import action +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.versioning import URLPathVersioning +from tool_instance.tool_processor import ToolProcessor +from unstract.tool_registry.dto import Tool +from unstract.tool_registry.tool_registry import ToolRegistry +from utils.filtering import FilterHelper +from workflow_manager.endpoint.destination import DestinationConnector +from workflow_manager.endpoint.endpoint_utils import WorkflowEndpointUtils +from workflow_manager.endpoint.source import SourceConnector +from workflow_manager.workflow.constants import WorkflowKey +from workflow_manager.workflow.dto import ExecutionResponse +from workflow_manager.workflow.enums import SchemaEntity, SchemaType +from workflow_manager.workflow.exceptions import ( + InvalidRequest, + WorkflowDoesNotExistError, + WorkflowExecutionBadRequestException, + WorkflowExecutionError, + WorkflowGenerationError, + WorkflowRegenerationError, +) +from workflow_manager.workflow.generator import WorkflowGenerator +from workflow_manager.workflow.models.workflow import Workflow +from workflow_manager.workflow.serializers import ( + ExecuteWorkflowResponseSerializer, + ExecuteWorkflowSerializer, + WorkflowSerializer, +) +from workflow_manager.workflow.workflow_helper import ( + WorkflowHelper, + WorkflowSchemaHelper, +) + +logger = logging.getLogger(__name__) + + +def update_pipeline( + pipeline_guid: Optional[str], status: tuple[str, str] +) -> Any: + if pipeline_guid: + pipeline: Pipeline = PipelineProcessor.fetch_pipeline( + pipeline_id=pipeline_guid + ) + PipelineProcessor.update_pipeline_status( + pipeline=pipeline, is_end=True, status=status + ) + + +def make_execution_response(response: ExecutionResponse) -> Any: + return ExecuteWorkflowResponseSerializer(response).data + + +def handle_false(string: str) -> bool: + if string.lower() == "false": + return False + else: + return True + + +class WorkflowViewSet(viewsets.ModelViewSet): + versioning_class = URLPathVersioning + permission_classes = [IsOwner] + queryset = Workflow.objects.all() + + def get_queryset(self) -> QuerySet: + filter_args = FilterHelper.build_filter_args( + self.request, + RequestKey.PROJECT, + WorkflowKey.WF_OWNER, + WorkflowKey.WF_IS_ACTIVE, + ) + queryset = ( + Workflow.objects.filter(created_by=self.request.user, **filter_args) + if filter_args + else Workflow.objects.filter(created_by=self.request.user) + ) + order_by = self.request.query_params.get("order_by") + if order_by == "desc": + queryset = queryset.order_by("-modified_at") + elif order_by == "asc": + queryset = queryset.order_by("modified_at") + + return queryset + + def get_serializer_class(self) -> serializers.Serializer: + if self.action == "execute": + return ExecuteWorkflowSerializer + else: + return WorkflowSerializer + + def _generate_workflow(self, workflow_id: str) -> WorkflowGenerator: + registry_tools: list[Tool] = ToolProcessor.get_registry_tools() + generator = WorkflowGenerator(workflow_id=workflow_id) + generator.set_request(self.request) + generator.generate_workflow(registry_tools) + return generator + + def perform_update(self, serializer: WorkflowSerializer) -> Workflow: + """To edit a workflow. Regenerates the tool instances for a new prompt. + + Raises: WorkflowGenerationError + """ + kwargs = {} + if serializer.validated_data.get(WorkflowKey.PROMPT_TEXT): + workflow: Workflow = self.get_object() + generator = self._generate_workflow(workflow_id=workflow.id) + kwargs = { + WorkflowKey.LLM_RESPONSE: generator.llm_response, + WorkflowKey.WF_IS_ACTIVE: True, + } + try: + workflow = serializer.save(**kwargs) + return workflow + except Exception as e: + logger.error(f"Error saving workflow to DB: {e}") + raise WorkflowRegenerationError + + def perform_create(self, serializer: WorkflowSerializer) -> Workflow: + """To create a new workflow. Creates the Workflow instance first and + uses it to generate the tool instances. + + Raises: WorkflowGenerationError + """ + try: + workflow = serializer.save( + is_active=True, + ) + WorkflowEndpointUtils.create_endpoints_for_workflow(workflow) + + # Enable GCS configurations to create GCS while creating a workflow + if ( + settings.GOOGLE_STORAGE_ACCESS_KEY_ID + and settings.UNSTRACT_FREE_STORAGE_BUCKET_NAME + ): + ConnectorInstanceHelper.create_default_gcs_connector( + workflow, self.request.user + ) + + except Exception as e: + logger.error(f"Error saving workflow to DB: {e}") + raise WorkflowGenerationError + return workflow + + def get_execution(self, request: Request, pk: str) -> Response: + execution = WorkflowHelper.get_current_execution(pk) + return Response( + make_execution_response(execution), status=status.HTTP_200_OK + ) + + def get_error_from_serializer( + self, error_details: dict[str, Any] + ) -> Optional[str]: + """Validation error.""" + error_key = next(iter(error_details)) + # Get the first error message + error_message: str = f"{error_details[error_key][0]} : {error_key}" + return error_message + + def get_workflow_by_id_or_project_id( + self, + workflow_id: Optional[str] = None, + project_id: Optional[str] = None, + ) -> Workflow: + """Retrieve workflow by workflow id or project Id. + + Args: + workflow_id (Optional[str], optional): workflow Id. + project_id (Optional[str], optional): Project Id. + + Raises: + WorkflowDoesNotExistError: _description_ + + Returns: + Workflow: workflow + """ + if workflow_id: + workflow = WorkflowHelper.get_workflow_by_id(workflow_id) + elif project_id: + workflow = WorkflowHelper.get_active_workflow_by_project_id( + project_id + ) + else: + raise WorkflowDoesNotExistError() + return workflow + + def execute( + self, + request: Request, + pipeline_guid: Optional[str] = None, + with_log: Optional[bool] = None, + ) -> Response: + if with_log is not None: + # Handle string field + with_log = handle_false(str(with_log)) + + self.serializer_class = ExecuteWorkflowSerializer + serializer = ExecuteWorkflowSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + workflow_id = serializer.get_workflow_id(serializer.validated_data) + project_id = serializer.get_project_id(serializer.validated_data) + execution_id = serializer.get_execution_id(serializer.validated_data) + execution_action = serializer.get_execution_action( + serializer.validated_data + ) + file_objs = request.FILES.getlist("files") + hashes_of_files = {} + if file_objs and execution_id and workflow_id: + hashes_of_files = SourceConnector.add_input_file_to_api_storage( + workflow_id=workflow_id, + execution_id=execution_id, + file_objs=file_objs, + ) + + try: + workflow = self.get_workflow_by_id_or_project_id( + workflow_id=workflow_id, project_id=project_id + ) + execution_response = self.execute_workflow( + workflow=workflow, + execution_action=execution_action, + execution_id=execution_id, + pipeline_guid=pipeline_guid, + with_log=with_log, + hash_values_of_files=hashes_of_files, + ) + return Response( + make_execution_response(execution_response), + status=status.HTTP_200_OK, + ) + except (InvalidRequest, WorkflowExecutionError) as exception: + update_pipeline(pipeline_guid, Pipeline.PipelineStatus.FAILURE) + raise exception + except Exception as exception: + logger.error(f"Error while executing workflow: {exception}") + update_pipeline(pipeline_guid, Pipeline.PipelineStatus.FAILURE) + if file_objs and execution_id and workflow_id: + DestinationConnector.delete_api_storage_dir( + workflow_id=workflow_id, execution_id=execution_id + ) + raise exception + + def execute_workflow( + self, + workflow: Workflow, + execution_action: Optional[str] = None, + execution_id: Optional[str] = None, + pipeline_guid: Optional[str] = None, + with_log: Optional[bool] = None, + hash_values_of_files: dict[str, str] = {}, + ) -> ExecutionResponse: + if execution_action is not None: + # Step execution + execution_response = WorkflowHelper.step_execution( + workflow, + execution_action, + execution_id=execution_id, + hash_values_of_files=hash_values_of_files, + ) + elif pipeline_guid: + # pipeline execution + update_pipeline(pipeline_guid, Pipeline.PipelineStatus.INPROGRESS) + execution_response = WorkflowHelper.complete_execution( + workflow=workflow, + execution_id=execution_id, + pipeline_id=pipeline_guid, + log_required=with_log, + hash_values_of_files=hash_values_of_files, + ) + update_pipeline(pipeline_guid, Pipeline.PipelineStatus.SUCCESS) + else: + execution_response = WorkflowHelper.complete_execution( + workflow=workflow, + execution_id=execution_id, + log_required=with_log, + hash_values_of_files=hash_values_of_files, + ) + return execution_response + + def activate(self, request: Request, pk: str) -> Response: + workflow = WorkflowHelper.active_project_workflow(pk) + serializer = WorkflowSerializer(workflow) + return Response(serializer.data, status=status.HTTP_200_OK) + + @action(detail=True, methods=["get"]) + def clear_cache( + self, request: Request, *args: Any, **kwargs: Any + ) -> Response: + workflow = self.get_object() + response: dict[str, Any] = WorkflowHelper.clear_cache( + workflow_id=workflow.id + ) + return Response(response.get("message"), status=response.get("status")) + + @action(detail=True, methods=["get"]) + def clear_file_marker( + self, request: Request, *args: Any, **kwargs: Any + ) -> Response: + workflow = self.get_object() + response: dict[str, Any] = WorkflowHelper.clear_file_marker( + workflow_id=workflow.id + ) + return Response(response.get("message"), status=response.get("status")) + + @action(detail=False, methods=["get"]) + def get_schema( + self, request: Request, *args: Any, **kwargs: Any + ) -> Response: + """Retrieves the JSON schema for source/destination type modules for + entities file/API/DB. + + Takes query params `type` (defaults to "src") and + `entity` (defaults to "file"). + + Returns: + Response: JSON schema for the request made + """ + schema_type = request.query_params.get("type", SchemaType.SRC.value) + schema_entity = request.query_params.get( + "entity", SchemaEntity.FILE.value + ) + + WorkflowSchemaHelper.validate_request( + schema_type=SchemaType(schema_type), + schema_entity=SchemaEntity(schema_entity), + ) + json_schema = WorkflowSchemaHelper.get_json_schema( + schema_type=schema_type, schema_entity=schema_entity + ) + return Response(data=json_schema, status=status.HTTP_200_OK) + + @action(detail=True, methods=["GET"]) + def workflow_settings_schema(self, request: HttpRequest) -> Response: + tool_registry = ToolRegistry() + schema = tool_registry.get_project_settings_schema() + return Response(schema) + + @action(detail=True, methods=["GET", "PUT"]) + def workflow_settings(self, request: HttpRequest, pk: str) -> Response: + workflow = self.get_object() + tool_registry = ToolRegistry() + if request.method == "GET": + schema = tool_registry.get_project_settings_schema() + return Response({"schema": schema, "settings": workflow.settings}) + + elif request.method == "PUT": + schema = tool_registry.get_project_settings_schema() + + try: + tool_registry.validate_schema_with_data(request.data, schema) + except Exception as e: + logger.error(f"Invalid input data {str(e)}") + raise WorkflowExecutionBadRequestException("Invalid input") + + workflow.settings = request.data + workflow.save() + return Response( + {"message": "Settings updated successfully"}, + status=status.HTTP_200_OK, + ) diff --git a/backend/workflow_manager/workflow/workflow_helper.py b/backend/workflow_manager/workflow/workflow_helper.py new file mode 100644 index 000000000..1e0a720f2 --- /dev/null +++ b/backend/workflow_manager/workflow/workflow_helper.py @@ -0,0 +1,728 @@ +import json +import logging +import os +import traceback +import uuid +from typing import Any, Optional + +from account.cache_service import CacheService +from account.models import Organization +from celery import current_task +from celery import exceptions as celery_exceptions +from celery import shared_task +from celery.result import AsyncResult +from django.conf import settings +from django.db import IntegrityError, connection +from django_tenants.utils import get_tenant_model, tenant_context +from redis import StrictRedis +from rest_framework import serializers +from tool_instance.constants import ToolInstanceKey +from tool_instance.models import ToolInstance +from tool_instance.tool_instance_helper import ToolInstanceHelper +from unstract.workflow_execution.enums import LogComponent, LogState +from unstract.workflow_execution.exceptions import StopExecution +from utils.request import feature_flag +from workflow_manager.endpoint.destination import DestinationConnector +from workflow_manager.endpoint.source import SourceConnector +from workflow_manager.workflow.constants import ( + CeleryConfigurations, + WorkflowErrors, + WorkflowExecutionKey, + WorkflowMessages, +) +from workflow_manager.workflow.dto import AsyncResultData, ExecutionResponse +from workflow_manager.workflow.enums import ( + ExecutionStatus, + SchemaEntity, + SchemaType, +) +from workflow_manager.workflow.exceptions import ( + InvalidRequest, + TaskDoesNotExistError, + WorkflowDoesNotExistError, + WorkflowExecutionNotExist, +) +from workflow_manager.workflow.execution import WorkflowExecutionServiceHelper +from workflow_manager.workflow.file_history_helper import FileHistoryHelper +from workflow_manager.workflow.models.execution import WorkflowExecution +from workflow_manager.workflow.models.workflow import Workflow + +logger = logging.getLogger(__name__) + + +class WorkflowHelper: + @staticmethod + def get_workflow_by_id(id: str) -> Workflow: + try: + workflow: Workflow = Workflow.objects.get(pk=id) + if not workflow or workflow is None: + raise WorkflowDoesNotExistError() + return workflow + except Workflow.DoesNotExist: + logger.error(f"Error getting workflow: {id}") + raise WorkflowDoesNotExistError() + + @staticmethod + def get_active_workflow_by_project_id(project_id: str) -> Workflow: + try: + workflow: Workflow = Workflow.objects.filter( + project_id=project_id, is_active=True + ).first() + if not workflow or workflow is None: + raise WorkflowDoesNotExistError() + return workflow + except Workflow.DoesNotExist: + raise WorkflowDoesNotExistError() + + @staticmethod + def active_project_workflow(workflow_id: str) -> Workflow: + workflow: Workflow = WorkflowHelper.get_workflow_by_id(workflow_id) + workflow.is_active = True + workflow.save() + return workflow + + @staticmethod + def build_workflow_execution_service( + organization_id: Optional[str], + workflow: Workflow, + tool_instances: list[ToolInstance], + pipeline_id: Optional[str], + single_step: bool, + scheduled: bool, + execution_mode: tuple[str, str], + workflow_execution: Optional[WorkflowExecution], + ) -> WorkflowExecutionServiceHelper: + workflow_execution_service = WorkflowExecutionServiceHelper( + organization_id=organization_id, + workflow=workflow, + tool_instances=tool_instances, + pipeline_id=pipeline_id, + single_step=single_step, + scheduled=scheduled, + mode=execution_mode, + workflow_execution=workflow_execution, + ) + workflow_execution_service.build() + return workflow_execution_service + + @staticmethod + def process_input_files( + workflow: Workflow, + source: SourceConnector, + destination: DestinationConnector, + execution_service: WorkflowExecutionServiceHelper, + single_step: bool, + hash_values_of_files: dict[str, str] = {}, + ) -> WorkflowExecution: + input_files = source.list_files_from_source() + total_files = len(input_files) + execution_service.publish_initial_workflow_logs(total_files) + for index, input_file in enumerate(input_files): + file_number = index + 1 + try: + WorkflowHelper.process_file( + current_step=file_number, + total_step=total_files, + input_file=input_file, + workflow=workflow, + source=source, + destination=destination, + execution_service=execution_service, + single_step=single_step, + hash_values_of_files=hash_values_of_files, + ) + except StopExecution: + break + execution_service.publish_final_workflow_logs() + return execution_service.get_execution_instance() + + @staticmethod + def process_file( + current_step: int, + total_step: int, + input_file: str, + workflow: Workflow, + source: SourceConnector, + destination: DestinationConnector, + execution_service: WorkflowExecutionServiceHelper, + single_step: bool, + hash_values_of_files: dict[str, str], + ) -> None: + file_history = None + error = None + file_name, file_hash = source.add_file_to_volume( + input_file_path=input_file, + hash_values_of_files=hash_values_of_files, + ) + try: + execution_service.initiate_tool_execution( + current_step, total_step, file_name, single_step + ) + file_history = FileHistoryHelper.get_file_history( + workflow=workflow, cache_key=file_hash + ) + execution_service.execute_input_file( + file_name=file_name, + single_step=single_step, + file_history=file_history, + ) + except StopExecution: + raise + except Exception as e: + execution_service.publish_log( + f"Error processing file {input_file}: {str(e)}" + ) + error = str(e) + execution_service.publish_update_log( + LogState.RUNNING, + f"{file_name} is processing", + LogComponent.DESTINATION, + ) + destination.handle_output( + file_name=file_name, + file_hash=file_hash, + workflow=workflow, + file_history=file_history, + error=error, + ) + execution_service.publish_update_log( + LogState.SUCCESS, + f"{file_name} is Processed successfully", + LogComponent.DESTINATION, + ) + + @staticmethod + def run_workflow( + workflow: Workflow, + hash_values_of_files: dict[str, str] = {}, + organization_id: Optional[str] = None, + pipeline_id: Optional[str] = None, + scheduled: bool = False, + single_step: bool = False, + workflow_execution: Optional[WorkflowExecution] = None, + execution_mode: Optional[tuple[str, str]] = None, + ) -> ExecutionResponse: + tool_instances: list[ + ToolInstance + ] = ToolInstanceHelper.get_tool_instances_by_workflow( + workflow.id, ToolInstanceKey.STEP + ) + execution_mode = execution_mode or WorkflowExecution.Mode.INSTANT + execution_service = WorkflowHelper.build_workflow_execution_service( + organization_id=organization_id, + workflow=workflow, + tool_instances=tool_instances, + pipeline_id=pipeline_id, + single_step=single_step, + scheduled=scheduled, + execution_mode=execution_mode, + workflow_execution=workflow_execution, + ) + execution_id = execution_service.execution_id + source = SourceConnector( + organization_id=organization_id, + workflow=workflow, + execution_id=execution_id, + execution_service=execution_service, + ) + destination = DestinationConnector( + workflow=workflow, execution_id=execution_id + ) + # Validating endpoints + source.validate() + destination.validate() + # Execution Process + try: + updated_execution = WorkflowHelper.process_input_files( + workflow, + source, + destination, + execution_service, + single_step=single_step, + hash_values_of_files=hash_values_of_files, + ) + log_id = str(execution_service.execution_log_id) + if log_id: + log_id = str(log_id) + return ExecutionResponse( + str(workflow.id), + str(updated_execution.id), + updated_execution.status, + log_id=log_id, + error=updated_execution.error_message, + mode=updated_execution.execution_mode, + result=destination.api_results, + ) + finally: + destination.delete_execution_directory() + + @staticmethod + def get_status_of_async_task( + execution_id: str, + ) -> ExecutionResponse: + """Get celery task status. + + Args: + execution_id (str): workflow execution id + + Raises: + TaskDoesNotExistError: Not found exception + + Returns: + ExecutionResponse: _description_ + """ + execution = WorkflowExecution.objects.get(id=execution_id) + + if not execution.task_id: + raise TaskDoesNotExistError() + + result = AsyncResult(str(execution.task_id)) + + task = AsyncResultData(async_result=result) + return ExecutionResponse( + execution.workflow_id, + execution_id, + task.status, + result=task.result, + ) + + @staticmethod + def execute_workflow_async( + workflow_id: str, + execution_id: str, + hash_values_of_files: dict[str, str], + timeout: int = -1, + pipeline_id: Optional[str] = None, + ) -> ExecutionResponse: + """Adding a workflow to the queue for execution. + + Args: + workflow_id (str): workflowId + execution_id (str): _description_ + timeout (int): celery timeout (timeout -1 : async execution) + pipeline_id (Optional[str], optional): optional pipeline. + Defaults to None. + + Returns: + ExecutionStatus: Existing status of execution + """ + try: + org_schema = connection.tenant.schema_name + async_execution = WorkflowHelper.execute_bin.delay( + org_schema, + workflow_id, + hash_values_of_files=hash_values_of_files, + execution_id=execution_id, + pipeline_id=pipeline_id, + ) + if timeout > -1: + async_execution.wait( + timeout=timeout, + interval=CeleryConfigurations.INTERVAL, + ) + task = AsyncResultData(async_result=async_execution) + logger.info(f"Job {async_execution} enqueued.") + celery_result = task.to_dict() + task_result = celery_result.get("result") + return ExecutionResponse( + workflow_id, + execution_id, + task.status, + result=task_result, + ) + except celery_exceptions.TimeoutError: + return ExecutionResponse( + workflow_id, + execution_id, + async_execution.status, + message=WorkflowMessages.CELERY_TIMEOUT_MESSAGE, + ) + except Exception as error: + WorkflowExecutionServiceHelper.update_execution_status( + execution_id, ExecutionStatus.ERROR + ) + logger.error(f"Errors while job enqueueing {str(error)}") + logger.error(f"Error {traceback.format_exc()}") + return ExecutionResponse( + workflow_id, + execution_id, + ExecutionStatus.ERROR.value, + error=str(error), + ) + + @staticmethod + @shared_task( + name="async_execute_bin", + acks_late=True, + autoretry_for=(Exception,), + max_retries=1, + retry_backoff=True, + retry_backoff_max=500, + retry_jitter=True, + ) + def execute_bin( + schema_name: str, + workflow_id: str, + execution_id: str, + hash_values_of_files: dict[str, str], + scheduled: bool = False, + execution_mode: Optional[tuple[str, str]] = None, + pipeline_id: Optional[str] = None, + ) -> Optional[list[Any]]: + """Asynchronous Execution By celery. + + Args: + schema_name (str): schema name to get Data + workflow_id (str): Workflow Id + execution_id (Optional[str], optional): Id of the execution. + Defaults to None. + scheduled (bool, optional): Represents if it is a scheduled + execution. Defaults to False. + execution_mode (Optional[WorkflowExecution.Mode]): + WorkflowExecution Mode. Defaults to None. + pipeline_id (Optional[str], optional): Id of pipeline. + Defaults to None. + + Returns: + dict[str, list[Any]]: Returns a dict with result from + workflow execution + """ + task_id = current_task.request.id + tenant: Organization = ( + get_tenant_model().objects.filter(schema_name=schema_name).first() + ) + with tenant_context(tenant): + workflow = Workflow.objects.get(id=workflow_id) + try: + workflow_execution = ( + WorkflowExecutionServiceHelper.create_workflow_execution( + workflow_id=workflow_id, + single_step=False, + pipeline_id=pipeline_id, + mode=WorkflowExecution.Mode.QUEUE, + execution_id=execution_id, + ) + ) + except IntegrityError: + # Use existing instance on retry attempt + workflow_execution = WorkflowExecution.objects.get( + pk=execution_id + ) + WorkflowExecutionServiceHelper.update_execution_task( + execution_id=execution_id, task_id=task_id + ) + result = WorkflowHelper.run_workflow( + workflow=workflow, + organization_id=schema_name, + pipeline_id=pipeline_id, + scheduled=scheduled, + workflow_execution=workflow_execution, + execution_mode=execution_mode, + hash_values_of_files=hash_values_of_files, + ).result + return result + + @staticmethod + def complete_execution( + workflow: Workflow, + execution_id: Optional[str] = None, + pipeline_id: Optional[str] = None, + log_required: Optional[bool] = True, + hash_values_of_files: dict[str, str] = {}, + ) -> ExecutionResponse: + # For scheduler workflow execution + if pipeline_id: + return WorkflowHelper.run_workflow(workflow=workflow) + + if log_required is not None and not log_required: + # Without log and log Id + if pipeline_id: + # pipeline scheduled execution + execution_id = str(uuid.uuid4()) + response: ExecutionResponse = ( + WorkflowHelper.execute_workflow_async( + workflow_id=workflow.id, + pipeline_id=pipeline_id, + execution_id=execution_id, + hash_values_of_files=hash_values_of_files, + ) + ) + return response + return WorkflowHelper.run_workflow(workflow=workflow) + if execution_id is None: + # Creating execution entity and return + return WorkflowHelper.create_and_make_execution_response( + workflow_id=workflow.id, pipeline_id=pipeline_id + ) + try: + # Normal execution + workflow_execution = WorkflowExecution.objects.get(pk=execution_id) + if ( + workflow_execution.status != ExecutionStatus.PENDING.value + or workflow_execution.execution_type + != WorkflowExecution.Type.COMPLETE + ): + raise InvalidRequest(WorkflowErrors.INVALID_EXECUTION_ID) + return WorkflowHelper.run_workflow( + workflow=workflow, + workflow_execution=workflow_execution, + hash_values_of_files=hash_values_of_files, + ) + except WorkflowExecution.DoesNotExist: + return WorkflowHelper.create_and_make_execution_response( + workflow_id=workflow.id, pipeline_id=pipeline_id + ) + + @staticmethod + def get_current_execution(execution_id: str) -> ExecutionResponse: + try: + workflow_execution = WorkflowExecution.objects.get(pk=execution_id) + return ExecutionResponse( + workflow_execution.workflow_id, + workflow_execution.id, + workflow_execution.status, + log_id=workflow_execution.project_settings_id, + error=workflow_execution.error_message, + mode=workflow_execution.execution_mode, + ) + except WorkflowExecution.DoesNotExist: + raise WorkflowExecutionNotExist() + + @staticmethod + def step_execution( + workflow: Workflow, + execution_action: str, + execution_id: Optional[str] = None, + hash_values_of_files: dict[str, str] = {}, + ) -> ExecutionResponse: + if ( + execution_action + is Workflow.ExecutionAction.START.value # type: ignore + ): + if execution_id is None: + return WorkflowHelper.create_and_make_execution_response( + workflow_id=workflow.id, single_step=True + ) + try: + workflow_execution = WorkflowExecution.objects.get( + pk=execution_id + ) + return WorkflowHelper.run_workflow( + workflow=workflow, + single_step=True, + workflow_execution=workflow_execution, + hash_values_of_files=hash_values_of_files, + ) + except WorkflowExecution.DoesNotExist: + return WorkflowHelper.create_and_make_execution_response( + workflow_id=workflow.id, single_step=True + ) + + else: + if execution_id is None: + raise InvalidRequest("execution_id is missed") + try: + workflow_execution = WorkflowExecution.objects.get( + pk=execution_id + ) + except WorkflowExecution.DoesNotExist: + raise WorkflowExecutionNotExist( + WorkflowErrors.INVALID_EXECUTION_ID + ) + if ( + workflow_execution.status != ExecutionStatus.PENDING.value + or workflow_execution.execution_type + != WorkflowExecution.Type.STEP + ): + raise InvalidRequest(WorkflowErrors.INVALID_EXECUTION_ID) + cache_service = CacheService() + current_action: Optional[str] = cache_service.get_a_key( + execution_id + ) + logger.info(f"workflow_execution.current_action {current_action}") + if current_action is None: + raise InvalidRequest(WorkflowErrors.INVALID_EXECUTION_ID) + cache_service.set_a_key(execution_id, execution_action) + workflow_execution = WorkflowExecution.objects.get(pk=execution_id) + + return ExecutionResponse( + workflow.id, + execution_id, + workflow_execution.status, + log_id=workflow_execution.project_settings_id, + error=workflow_execution.error_message, + mode=workflow_execution.execution_mode, + ) + + @staticmethod + def create_and_make_execution_response( + workflow_id: str, + pipeline_id: Optional[str] = None, + single_step: bool = False, + mode: tuple[str, str] = WorkflowExecution.Mode.INSTANT, + ) -> ExecutionResponse: + workflow_execution = ( + WorkflowExecutionServiceHelper.create_workflow_execution( + workflow_id=workflow_id, + single_step=single_step, + pipeline_id=pipeline_id, + mode=mode, + ) + ) + return ExecutionResponse( + workflow_execution.workflow_id, + workflow_execution.id, + workflow_execution.status, + log_id=workflow_execution.project_settings_id, + error=workflow_execution.error_message, + mode=workflow_execution.execution_mode, + ) + + # TODO: Access cache through a manager + @staticmethod + def clear_cache(workflow_id: str) -> dict[str, Any]: + """Function to clear cache with a specific pattern.""" + + # TODO: Clear this section if not needed + cache = StrictRedis( + host=settings.REDIS_HOST, + port=int(settings.REDIS_PORT), + password=settings.REDIS_PASSWORD, + username=settings.REDIS_USER, + ) + response: dict[str, Any] = {} + try: + keys = cache.scan_iter(f"cache:{workflow_id}*") + for key in keys: + if cache.get(key): + cache.delete(key) + logger.info(f"Successfully Cleared Cache, deleted {key!r}") + else: + logger.info(f"No key {key!r} exists in cache") + response["message"] = WorkflowMessages.CACHE_CLEAR_SUCCESS + response["status"] = 200 + return response + except Exception as exc: + logger.error(f"Error occurred while clearing cache : {exc}") + response["message"] = WorkflowMessages.CACHE_CLEAR_FAILED + response["status"] = 400 + return response + + @staticmethod + def clear_file_marker(workflow_id: str) -> dict[str, Any]: + """Function to clear file marker from the cache.""" + # Clear file history from the table + response: dict[str, Any] = {} + workflow = Workflow.objects.get(id=workflow_id) + try: + FileHistoryHelper.clear_history_for_workflow(workflow=workflow) + response["message"] = WorkflowMessages.FILE_MARKER_CLEAR_SUCCESS + response["status"] = 200 + return response + except Exception as exc: + logger.error(f"Error occurred while clearing file marker : {exc}") + response["message"] = WorkflowMessages.FILE_MARKER_CLEAR_FAILED + response["status"] = 400 + return response + + @staticmethod + def get_workflow_execution_id(execution_id: str) -> str: + wf_exec_prefix = WorkflowExecutionKey.WORKFLOW_EXECUTION_ID_PREFIX + workflow_execution_id = f"{wf_exec_prefix}-{execution_id}" + return workflow_execution_id + + @staticmethod + def get_execution_by_id(execution_id: str) -> WorkflowExecution: + try: + execution: WorkflowExecution = WorkflowExecution.objects.get( + id=execution_id + ) + return execution + except WorkflowExecution.DoesNotExist: + raise WorkflowDoesNotExistError() + + @staticmethod + def make_async_result(obj: AsyncResult) -> dict[str, Any]: + return { + "id": obj.id, + "status": obj.status, + "result": obj.result, + "is_ready": obj.ready(), + "is_failed": obj.failed(), + "info": obj.info, + } + + +class WorkflowSchemaHelper: + """Helper class for workflow schema related methods.""" + + @staticmethod + def validate_request( + schema_type: SchemaType, schema_entity: SchemaEntity + ) -> bool: + """Validates the given args for reading the JSON schema. + + Schema type of `src`, allows entities `file` and `api` + Schema type of `dest`, allows entities `db` + + Args: + schema_type (SchemaType): Enum with values `src`, `dest` + schema_entity (SchemaEntity): Enum with values `file`, `api`, `db` + + Raises: + serializers.ValidationError: If invalid values/ + combination is requested + + Returns: + bool: _description_ + """ + possible_types = [e.value for e in SchemaType] + possible_entities = [e.value for e in SchemaEntity] + + if schema_type.value not in possible_types: + raise serializers.ValidationError( + f"Invalid value for 'type': {schema_type.value}, " + f"should be one of {possible_types}" + ) + + if schema_entity.value not in possible_entities: + raise serializers.ValidationError( + f"Invalid value for 'entity': {schema_entity.value}, " + f"should be one of {possible_entities}" + ) + + if ( + schema_type == SchemaType.SRC and schema_entity == SchemaEntity.DB + ) or ( + schema_type == SchemaType.DEST and schema_entity != SchemaEntity.DB + ): + raise serializers.ValidationError( + f"Invalid values for 'type': {schema_type.value}, " + f"'entity': {schema_entity.value}." + f"Param 'type': {SchemaType.SRC.value} allows " + f"{SchemaEntity.FILE.value} and {SchemaEntity.API.value}" + f"'type': {SchemaType.DEST.value} allows " + f"{SchemaEntity.DB.value}." + ) + return True + + @staticmethod + def get_json_schema( + schema_type: SchemaType, schema_entity: SchemaEntity + ) -> dict[str, Any]: + """Reads and returns the JSON schema for the given args. + + Args: + schema_type (SchemaType): Enum with values `src`, `dest` + schema_entity (SchemaEntity): Enum with values `file`, `api`, `db` + + Returns: + dict[str, Any]: JSON schema for the requested entity + """ + schema_path = ( + f"{os.path.dirname(__file__)}/static/" + f"{schema_type}/{schema_entity}.json" + ) + with open(schema_path, encoding="utf-8") as file: + schema = json.load(file) + return schema # type: ignore diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 000000000..6641ec495 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,63 @@ +# DOCKER BUILD +We can build the dockers locally using the below command + +``` +VERSION=test docker compose -f docker-compose.build.yaml build +``` + +Here `VERSION` env will be the docker tag version we need to use. For local testing we can pass any value. We can use the same compose files for building and publishing our dockers in our CI/CD systems as well. + +If some one needs to build only one of the services they can do it by running build for that alone + +Eg:- + +``` +VERSION=test docker compose -f docker-compose.build.yaml build frontend +``` + +# DOCKER RUN + +NOTE: copy sample.*.env files into *.env and make required changes in it before running `docker compose up` + +We can use the `docker compose up` command to run all the required services. Make sure build is done before the run and to use the same `VERSION`. + +``` +VERSION=test docker compose -f docker-compose.yaml up -d +``` + +Now you should be able to access your frontend at http://frontend.unstract.localhost + + +# `src` FOLDER LAYOUT AND `gunicorn` + +For the following project structure: + +```bash +scheduler + |- src + | |- unstract + | |- scheduler + | |- main.py + |- pdm.lock + |- pyproject.toml +``` + +Add the following in `pyproject.toml` to detect package in `src`: + +```pyproject.toml +[tool.pdm.build] +includes = ["src"] +package-dir = "src" +``` + +This will install the project to: + +```bash +.venv/lib/python3.12/site-packages/unstract/scheduler/main.py +``` + +This will allow `gunicorn` to refer the package directly as: + +```bash +$ gunicorn "-c" "python:unstract.scheduler.config.gunicorn" "unstract.scheduler.main:app" +``` diff --git a/docker/docker-compose-dev-essentials.yaml b/docker/docker-compose-dev-essentials.yaml new file mode 100644 index 000000000..d52230ee0 --- /dev/null +++ b/docker/docker-compose-dev-essentials.yaml @@ -0,0 +1,121 @@ +version: '3.7' + +services: + db: + # Supports pgvector for doc indexer + image: 'ankane/pgvector:v0.5.1' + container_name: unstract-db + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data/ + - ../backend/init.sql:/docker-entrypoint-initdb.d/init.sql + env_file: + - ./essentials.env + labels: + - traefik.enable=false + + redis: + image: 'bitnami/redis:7.0.14' + container_name: unstract-redis + ports: + - "6379:6379" + environment: + - ALLOW_EMPTY_PASSWORD=yes + volumes: + - redis_data:/var/lib/redis/data/ + labels: + - traefik.enable=false + + minio: + image: 'minio/minio:latest' + container_name: unstract-minio + hostname: minio + ports: + - '9000:9000' + - '9001:9001' + volumes: + - minio_data:/data + env_file: + - ./essentials.env + command: server /data --console-address ":9001" + labels: + - traefik.enable=true + - traefik.http.routers.minio.rule=Host(`minio.unstract.localhost`) + - traefik.http.services.minio.loadbalancer.server.port=9001 + + reverse-proxy: + # The official v2 Traefik docker image + image: traefik:v2.10 + container_name: unstract-proxy + # - Enables the web UI. + # - Tells Traefik to use docker and file providers. + # - Direct Traefik to the correct network for docker provider. + # This is required because Traefik by default tries available networks in a + # round-robin fashion. With multiple providers, services can be on multiple + # networks causing 504 Gateway Timeout. + command: + --api.insecure=true + --accesslog=true --log.level=INFO + --providers.docker=true --providers.docker.network=unstract-network + --providers.file.filename=/proxy_overrides.yaml --providers.file.watch=true + ports: + # The HTTP port + - "80:80" + # The Web UI (enabled by --api.insecure=true) + - "8080:8080" + volumes: + # So that Traefik can listen to the Docker events + - /var/run/docker.sock:/var/run/docker.sock + # Proxy overrides for components run directly in Docker host + - ./proxy_overrides.yaml:/proxy_overrides.yaml + # Since any proxy overrides need to point to Docker host for relevant routes. + extra_hosts: + # "host-gateway" is a special string that translates to host docker0 i/f IP. + - "host.docker.internal:host-gateway" + + feature-flag: + image: flipt/flipt:v1.34.0 # Dated(05/01/2024) Latest stable version. Ref:https://github.com/flipt-io/flipt/releases + container_name: unstract-flipt + restart: always + ports: # Forwarded to available host ports + - "8082:8080" # REST API port + - "9005:9000" # gRPC port + # https://www.flipt.io/docs/configuration/overview#environment-variables) + # https://www.flipt.io/docs/configuration/overview#configuration-parameters + env_file: + - ./essentials.env + environment: + FLIPT_CACHE_ENABLED: true + labels: + - traefik.enable=true + - traefik.http.routers.feature-flag.rule=Host(`feature-flag.unstract.localhost`) + - traefik.http.services.feature-flag.loadbalancer.server.port=8080 + + unstract-io: + image: downloads.unstructured.io/unstructured-io/unstructured-api:0.0.61 + container_name: unstract-unstructured-io + ports: # Forwarded to available host ports + - "8083:8000" + labels: + - traefik.enable=false + + qdrant: + # Supports pgvector for doc indexer + image: 'qdrant/qdrant' + container_name: unstract-vector-db + ports: + - "6333:6333" + volumes: + - qdrant_data:/var/lib/qdrant/data/ + labels: + - traefik.enable=false + env_file: + - ./essentials.env + +volumes: + flipt_data: + minio_data: + postgres_data: + qdrant_data: + redis_data: diff --git a/docker/docker-compose.build.yaml b/docker/docker-compose.build.yaml new file mode 100644 index 000000000..84e5e836e --- /dev/null +++ b/docker/docker-compose.build.yaml @@ -0,0 +1,38 @@ +version: '3.7' + +services: + frontend: + image: unstract/frontend:${VERSION} + build: + dockerfile: docker/dockerfiles/frontend.Dockerfile + context: .. + backend: + image: unstract/backend:${VERSION} + build: + dockerfile: docker/dockerfiles/backend.Dockerfile + context: .. + worker: + image: unstract/worker:${VERSION} + build: + dockerfile: docker/dockerfiles/worker.Dockerfile + context: .. + platform-service: + image: unstract/platform-service:${VERSION} + build: + dockerfile: docker/dockerfiles/platform.Dockerfile + context: .. + document-service: + image: unstract/document-service:${VERSION} + build: + dockerfile: docker/dockerfiles/document.Dockerfile + context: .. + prompt-service: + image: unstract/prompt-service:${VERSION} + build: + dockerfile: docker/dockerfiles/prompt.Dockerfile + context: .. + x2text-service: + image: unstract/x2text-service:${VERSION} + build: + dockerfile: docker/dockerfiles/x2text.Dockerfile + context: .. diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml new file mode 100644 index 000000000..6f4442c66 --- /dev/null +++ b/docker/docker-compose.yaml @@ -0,0 +1,165 @@ +version: '3.7' +include: + - docker-compose-dev-essentials.yaml + +services: + # Backend service + backend: + image: unstract/backend:${VERSION} + container_name: unstract-backend + command: migrate + ports: + - "8000:8000" + env_file: + - ../backend/.env + depends_on: + - db + - redis + - reverse-proxy + - minio + volumes: + - ./workflow_data:/data + environment: + - ENVIRONMENT=development + labels: + - traefik.enable=true + - traefik.http.routers.backend.rule=Host(`frontend.unstract.localhost`) && PathPrefix(`/api/v1`, `/deployment`) + + # Celery execution consumer + execution-consumer: + image: unstract/backend:${VERSION} + container_name: unstract-execution-consumer + entrypoint: /app/.venv/bin/celery + command: "-A backend worker --loglevel=info" + env_file: + - ../backend/.env + depends_on: + - redis + environment: + - ENVIRONMENT=development + labels: + - traefik.enable=false + volumes: + - ./workflow_data:/data + + # Celery Flower + celery-flower: + image: unstract/backend:${VERSION} + container_name: unstract-celery-flower + entrypoint: /app/.venv/bin/celery + command: "-A backend flower --port=5555" + env_file: + - ../backend/.env + depends_on: + - execution-consumer + - redis + labels: + - traefik.enable=false + ports: + - "5555:5555" + environment: + - ENVIRONMENT=development + volumes: + - unstract_data:/data + + # Celery Beat + celery-beat: + image: unstract/backend:${VERSION} + container_name: unstract-celery-beat + entrypoint: /app/.venv/bin/celery + command: "-A backend beat --scheduler django_celery_beat.schedulers:DatabaseScheduler -l INFO" + env_file: + - ../backend/.env + - ./essentials.env + restart: on-failure + depends_on: + - db + - redis + + # Frontend React app + frontend: + image: unstract/frontend:${VERSION} + container_name: unstract-frontend + ports: + - "3000:3000" + depends_on: + - backend + - reverse-proxy + environment: + - ENVIRONMENT=development + labels: + - traefik.enable=true + - traefik.http.routers.frontend.rule=Host(`frontend.unstract.localhost`) + + platform-service: + image: unstract/platform-service:${VERSION} + container_name: unstract-platform-service + ports: + - "3001:3001" + env_file: + - ../platform-service/.env + depends_on: + - redis + - db + labels: + - traefik.enable=false + + prompt-service: + image: unstract/prompt-service:${VERSION} + container_name: unstract-prompt-service + ports: + - "3003:3003" + env_file: + - ../prompt-service/.env + labels: + - traefik.enable=false + + x2text-service: + image: unstract/x2text-service:${VERSION} + container_name: unstract-x2text-service + ports: + - "3004:3004" + env_file: + - ../x2text-service/.env + depends_on: + - db + labels: + - traefik.enable=false + + worker: + image: unstract/worker:${VERSION} + container_name: unstract-worker + ports: + - 5002:5002 + env_file: + - ../worker/.env + volumes: + - ./workflow_data:/data + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + - redis + labels: + - traefik.enable=false + + document: + image: unstract/document-service:${VERSION} + container_name: unstract-document-service + ports: + - 3002:3002 + depends_on: + - redis + env_file: + - ../document-service/.env + environment: + - ENVIRONMENT=development + labels: + - traefik.enable=false + +volumes: + unstract_data: + +networks: + default: + # NOTE: + # Any changes need to be reflected in proxy service too. + name: unstract-network diff --git a/docker/dockerfiles/backend.Dockerfile b/docker/dockerfiles/backend.Dockerfile new file mode 100644 index 000000000..13f5a791e --- /dev/null +++ b/docker/dockerfiles/backend.Dockerfile @@ -0,0 +1,59 @@ +FROM python:3.9-slim + +LABEL maintainer="Zipstack Inc." + +# Keeps Python from generating .pyc files in the container +ENV PYTHONDONTWRITEBYTECODE 1 +# Set to immediately flush stdout and stderr streams without first buffering +ENV PYTHONUNBUFFERED 1 +ENV PYTHONPATH /unstract + +ENV BUILD_CONTEXT_PATH backend +ENV BUILD_PACKAGES_PATH unstract +ENV DJANGO_SETTINGS_MODULE "backend.settings.production" +ENV PDM_VERSION 2.12.3 + +RUN apt-get update; \ + apt-get --no-install-recommends install -y \ + build-essential \ + ca-certificates \ + freetds-bin freetds-dev \ + gcc g++ \ + git \ + libffi-dev libmagic-dev libpoppler-cpp-dev libpq-dev \ + musl-dev \ + pkg-config poppler-utils \ + python3-dev \ + tesseract-ocr \ + libkrb5-dev; \ + apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*; \ + \ + pip install --no-cache-dir -U pip pdm~=${PDM_VERSION}; + +WORKDIR /app + +COPY ${BUILD_CONTEXT_PATH}/ . +# Copy local dependency packages +COPY ${BUILD_PACKAGES_PATH}/ /unstract + +RUN set -e; \ + \ + rm -rf .venv .pdm* .python* requirements.txt 2>/dev/null; \ + \ + pdm venv create -w virtualenv --with-pip; \ + # source command may not be availble in sh + . .venv/bin/activate; \ + \ + pdm sync --prod --no-editable; \ + \ + # REF: https://docs.gunicorn.org/en/stable/deploy.html#using-virtualenv + pip install --no-cache-dir gunicorn; + +EXPOSE 8000 + +# Creates a non-root user with an explicit UID and adds permission to access the /app folder +# For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers +RUN adduser -u 5678 --disabled-password --gecos "" unstract; \ + chown -R unstract /app /unstract; + +ENTRYPOINT [ "./entrypoint.sh" ] diff --git a/docker/dockerfiles/backend.Dockerfile.dockerignore b/docker/dockerfiles/backend.Dockerfile.dockerignore new file mode 100644 index 000000000..d0c9f62a2 --- /dev/null +++ b/docker/dockerfiles/backend.Dockerfile.dockerignore @@ -0,0 +1,40 @@ +**/__pycache__ +**/.venv +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/bin +**/charts +**/docker-compose* +**/compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +!README.md +__pycache__ +*.pyc +*.pyo +*.db +*.sqlite3 +*.log +*.tmp +*.swp +*.swo +*.bak +*.idea +*.vscode +*.git diff --git a/docker/dockerfiles/document.Dockerfile b/docker/dockerfiles/document.Dockerfile new file mode 100644 index 000000000..00420bb72 --- /dev/null +++ b/docker/dockerfiles/document.Dockerfile @@ -0,0 +1,58 @@ +FROM openjdk:8-jre-slim + +LABEL maintainer="Zipstack Inc." + +# Keeps Python from generating .pyc files in the container +ENV PYTHONDONTWRITEBYTECODE 1 +# Turns off buffering for easier container logging +ENV PYTHONUNBUFFERED=1 + +ENV BUILD_CONTEXT_PATH document-service +ENV PYTHON_VERSION 3.9 +ENV PDM_VERSION 2.12.3 + +RUN DEBIAN_FRONTEND=noninteractive apt-get update; \ + apt-get --no-install-recommends install -y \ + fonts-dejavu fonts-dejavu-core fonts-dejavu-extra fonts-droid-fallback fonts-dustin \ + fonts-f500 fonts-fanwood fonts-freefont-ttf \ + fonts-liberation fonts-lmodern fonts-lyx \ + fonts-opensymbol fonts-sil-gentium fonts-texgyre fonts-tlwg-purisa \ + hyphen-af hyphen-en-us \ + libreoffice-common \ + python${PYTHON_VERSION} python3-pip \ + software-properties-common \ + unoconv; \ + apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*; \ + \ + pip install --no-cache-dir -U pip pdm~=${PDM_VERSION}; + +EXPOSE 3002 + +WORKDIR /app + +COPY ${BUILD_CONTEXT_PATH}/ . + +RUN set -e; \ + \ + rm -rf .venv .pdm* .python* requirements.txt 2>/dev/null; \ + \ + pdm venv create -w virtualenv --with-pip; \ + # source command may not be availble in sh + . .venv/bin/activate; \ + \ + pdm sync --prod --no-editable; \ + \ + # REF: https://docs.gunicorn.org/en/stable/deploy.html#using-virtualenv + pip install --no-cache-dir gunicorn; + +RUN mkdir /app/uploads /app/processed; + +# Creates a non-root user with an explicit UID and adds permission to access the /app folder +# For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers +RUN adduser -u 5678 --disabled-password --gecos "" unstract; \ + chown -R unstract /app; + +USER unstract + +# Wrapper to run both python server and libreoffice. +CMD [ "/app/wrapper.sh" ] diff --git a/docker/dockerfiles/document.Dockerfile.dockerignore b/docker/dockerfiles/document.Dockerfile.dockerignore new file mode 100644 index 000000000..d0c9f62a2 --- /dev/null +++ b/docker/dockerfiles/document.Dockerfile.dockerignore @@ -0,0 +1,40 @@ +**/__pycache__ +**/.venv +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/bin +**/charts +**/docker-compose* +**/compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +!README.md +__pycache__ +*.pyc +*.pyo +*.db +*.sqlite3 +*.log +*.tmp +*.swp +*.swo +*.bak +*.idea +*.vscode +*.git diff --git a/docker/dockerfiles/frontend.Dockerfile b/docker/dockerfiles/frontend.Dockerfile new file mode 100644 index 000000000..8c935ca39 --- /dev/null +++ b/docker/dockerfiles/frontend.Dockerfile @@ -0,0 +1,33 @@ +FROM node:16 AS builder + +ENV BUILD_CONTEXT_PATH frontend +ENV REACT_APP_BACKEND_URL "" + +# Set the working directory inside the container +WORKDIR /app + +COPY ${BUILD_CONTEXT_PATH}/ . + +RUN set -e; \ + # Install app dependencies + npm install --ignore-scripts; \ + # Build the React app + npm run build; + + +FROM nginx:1.25 + +LABEL maintainer="Zipstack Inc." + +# Remove the default NGINX configuration +# RUN rm /etc/nginx/conf.d/default.conf + +COPY --from=builder /app/build /usr/share/nginx/html +COPY --from=builder /app/nginx.conf /etc/nginx/nginx.conf + +EXPOSE 80 + +USER nginx + +# Start NGINX +CMD ["nginx", "-g", "daemon off;"] diff --git a/docker/dockerfiles/frontend.Dockerfile.dockerignore b/docker/dockerfiles/frontend.Dockerfile.dockerignore new file mode 100644 index 000000000..ce75dee14 --- /dev/null +++ b/docker/dockerfiles/frontend.Dockerfile.dockerignore @@ -0,0 +1,12 @@ +# Items that don't need to be in a Docker image. +# Anything not used by the build system should go here. +**/Dockerfile +**/.dockerignore +**/.gitignore +**/README.md +**/.env + +# Artifacts that will be built during image creation. +# This should contain all files created during `npm run build`. +**/build +**/node_modules diff --git a/docker/dockerfiles/platform.Dockerfile b/docker/dockerfiles/platform.Dockerfile new file mode 100644 index 000000000..4c0fa9539 --- /dev/null +++ b/docker/dockerfiles/platform.Dockerfile @@ -0,0 +1,56 @@ +FROM python:3.9-slim + +LABEL maintainer="Zipstack Inc." + +# Keeps Python from generating .pyc files in the container +ENV PYTHONDONTWRITEBYTECODE 1 +# Set to immediately flush stdout and stderr streams without first buffering +ENV PYTHONUNBUFFERED 1 +ENV PYTHONPATH /unstract + +ENV BUILD_CONTEXT_PATH platform-service +ENV BUILD_PACKAGES_PATH unstract +ENV PDM_VERSION 2.12.3 + +RUN apt-get update; \ + apt-get --no-install-recommends install -y \ + ffmpeg \ + git \ + libmagic-dev libsm6 libxext6 \ + pandoc poppler-utils \ + tesseract-ocr \ + libreoffice; \ + apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*; \ + \ + pip install --no-cache-dir -U pip pdm~=${PDM_VERSION}; + +WORKDIR /app + +COPY ${BUILD_CONTEXT_PATH} . +# Copy local dependency packages +COPY ${BUILD_PACKAGES_PATH} /unstract + +RUN set -e; \ + \ + rm -rf .venv .pdm* .python* requirements.txt 2>/dev/null; \ + \ + pdm venv create -w virtualenv --with-pip; \ + # source command may not be availble in sh + . .venv/bin/activate; \ + \ + pdm sync --prod --no-editable; \ + \ + # REF: https://docs.gunicorn.org/en/stable/deploy.html#using-virtualenv + pip install --no-cache-dir gunicorn; + +EXPOSE 3001 + +# Creates a non-root user with an explicit UID and adds permission to access the /app folder +# For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers +RUN adduser -u 5678 --disabled-password --gecos "" unstract; \ + chown -R unstract /app /unstract; + +USER unstract + +# During debugging, this entry point will be overridden. For more information, please refer to https://aka.ms/vscode-docker-python-debug +CMD [".venv/bin/gunicorn", "--bind", "0.0.0.0:3001", "--timeout", "300", "unstract.platform_service.main:app"] diff --git a/docker/dockerfiles/platform.Dockerfile.dockerignore b/docker/dockerfiles/platform.Dockerfile.dockerignore new file mode 100644 index 000000000..20ca9015b --- /dev/null +++ b/docker/dockerfiles/platform.Dockerfile.dockerignore @@ -0,0 +1,8 @@ +.dockerignore +.env* +.git/ +.pytest_cache/ +__pycache__/ +.venv/ +.vscode/ +tests/ diff --git a/docker/dockerfiles/prompt.Dockerfile b/docker/dockerfiles/prompt.Dockerfile new file mode 100644 index 000000000..e79cc243a --- /dev/null +++ b/docker/dockerfiles/prompt.Dockerfile @@ -0,0 +1,82 @@ +FROM python:3.9 + +LABEL maintainer="Zipstack Inc." + +# Keeps Python from generating .pyc files in the container +ENV PYTHONDONTWRITEBYTECODE 1 +# Set to immediately flush stdout and stderr streams without first buffering +ENV PYTHONUNBUFFERED 1 + +ENV BUILD_CONTEXT_PATH prompt-service +ENV TARGET_PLUGINS_PATH src/unstract/prompt_service/plugins +ENV PDM_VERSION 2.12.3 + +RUN apt-get update; \ + apt-get --no-install-recommends install -y \ + freetds-bin freetds-dev \ + ffmpeg \ + git \ + libmagic-dev libsm6 libxext6 \ + libreoffice \ + pandoc poppler-utils \ + tesseract-ocr; \ + apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*; \ + \ + pip install --no-cache-dir -U pip pdm~=${PDM_VERSION}; + +WORKDIR /app + +COPY ${BUILD_CONTEXT_PATH} . + +RUN set -e; \ + \ + rm -rf .venv .pdm* .python* requirements.txt 2>/dev/null; \ + \ + pdm venv create -w virtualenv --with-pip; \ + # source command may not be availble in sh + . .venv/bin/activate; \ + \ + pdm sync --prod --no-editable; \ + \ + # + # Install plugins + # + for dir in "${TARGET_PLUGINS_PATH}"/*/; \ + do \ + # Remove trailing "/". \ + dirpath=${dir%*/}; \ + \ + # If no plugins, final part on split by "/" is equal to "*". \ + if [ "${dirpath##*/}" = "*" ]; then \ + continue; \ + fi; \ + \ + cd "$dirpath"; \ + echo "Installing plugin: ${dirpath##*/}..."; \ + \ + # PDM reuses active venv unless PDM_IGNORE_ACTIVE_VENV is set. + pdm sync --prod --no-editable; \ + \ + cd -; \ + done; \ + # + # + # + \ + # REF: https://docs.gunicorn.org/en/stable/deploy.html#using-virtualenv + pip install --no-cache-dir gunicorn; + +# Storage for prompt studio uploads +RUN mkdir prompt-studio-data + +EXPOSE 3003 + +# Creates a non-root user with an explicit UID and adds permission to access the /app folder +# For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers +RUN adduser -u 5678 --disabled-password --gecos "" unstract; \ + chown -R unstract /app; + +USER unstract + +# During debugging, this entry point will be overridden. For more information, please refer to https://aka.ms/vscode-docker-python-debug +CMD [".venv/bin/gunicorn", "--bind", "0.0.0.0:3003", "--timeout", "300", "unstract.prompt_service.main:app"] diff --git a/docker/dockerfiles/prompt.Dockerfile.dockerignore b/docker/dockerfiles/prompt.Dockerfile.dockerignore new file mode 100644 index 000000000..20ca9015b --- /dev/null +++ b/docker/dockerfiles/prompt.Dockerfile.dockerignore @@ -0,0 +1,8 @@ +.dockerignore +.env* +.git/ +.pytest_cache/ +__pycache__/ +.venv/ +.vscode/ +tests/ diff --git a/docker/dockerfiles/worker.Dockerfile b/docker/dockerfiles/worker.Dockerfile new file mode 100644 index 000000000..aae3d0e7d --- /dev/null +++ b/docker/dockerfiles/worker.Dockerfile @@ -0,0 +1,46 @@ +FROM python:3.9-slim + +LABEL maintainer="Zipstack Inc." + +# Keeps Python from generating .pyc files in the container +ENV PYTHONDONTWRITEBYTECODE 1 +# Set to immediately flush stdout and stderr streams without first buffering +ENV PYTHONUNBUFFERED 1 + +ENV BUILD_CONTEXT_PATH worker +ENV PDM_VERSION 2.12.3 + +RUN apt-get update \ + && apt-get --no-install-recommends install -y docker \ + && apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* \ + \ + && pip install --no-cache-dir -U pip pdm~=${PDM_VERSION} + +WORKDIR /app + +COPY ${BUILD_CONTEXT_PATH} . + +RUN set -e; \ + \ + rm -rf .venv .pdm* .python* requirements.txt 2>/dev/null; \ + \ + pdm venv create -w virtualenv --with-pip; \ + # source command may not be availble in sh + . .venv/bin/activate; \ + \ + pdm sync --prod --no-editable; \ + \ + # REF: https://docs.gunicorn.org/en/stable/deploy.html#using-virtualenv + pip install --no-cache-dir gunicorn gevent; + + +EXPOSE 5002 + +# Creates a non-root user with an explicit UID and adds permission to access the /app folder +# For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers +RUN adduser -u 5678 --disabled-password --gecos "" unstract; \ + chown -R unstract /app; + +# During debugging, this entry point will be overridden. For more information, please refer to https://aka.ms/vscode-docker-python-debug +# The suggested maximum concurrent requests when using workers and threads is (2*CPU)+1 +CMD [ "./entrypoint.sh" ] diff --git a/docker/dockerfiles/worker.Dockerfile.dockerignore b/docker/dockerfiles/worker.Dockerfile.dockerignore new file mode 100644 index 000000000..1abe474ac --- /dev/null +++ b/docker/dockerfiles/worker.Dockerfile.dockerignore @@ -0,0 +1,42 @@ +__pycache__ +.venv +.classpath +dockerignore +.env +.git +.gitignore +.project +.settings +.toolstarget +.vs +.vscode +*.*proj.user +*.dbmdl +*.jfm +bin +charts +docker-compose* +compose* +Dockerfile* +node_modules +npm-debug.log +obj +secrets.dev.yaml +values.dev.yaml +LICENSE +README.md +*.pyc +*.pyo +*.db +*.sqlite3 +*.log +*.tmp +*.swp +*.swo +*.bak +*.idea +*.vscode +*.git +*-log.txt +test*.py +*.drawio diff --git a/docker/dockerfiles/x2text.Dockerfile b/docker/dockerfiles/x2text.Dockerfile new file mode 100644 index 000000000..cc96570db --- /dev/null +++ b/docker/dockerfiles/x2text.Dockerfile @@ -0,0 +1,43 @@ +FROM python:3.9-slim + +LABEL maintainer="Zipstack Inc." + +# Keeps Python from generating .pyc files in the container +ENV PYTHONDONTWRITEBYTECODE 1 +# Set to immediately flush stdout and stderr streams without first buffering +ENV PYTHONUNBUFFERED 1 + +ENV BUILD_CONTEXT_PATH x2text-service +ENV PDM_VERSION 2.12.3 + +RUN pip install --no-cache-dir -U pip pdm~=${PDM_VERSION} + +WORKDIR /app + +COPY ${BUILD_CONTEXT_PATH} . + +RUN set -e; \ + \ + rm -rf .venv .pdm* .python* requirements.txt 2>/dev/null; \ + \ + pdm venv create -w virtualenv --with-pip; \ + # source command may not be availble in sh + . .venv/bin/activate; \ + \ + pdm sync --prod --no-editable; \ + \ + # REF: https://docs.gunicorn.org/en/stable/deploy.html#using-virtualenv + pip install --no-cache-dir gunicorn; + +EXPOSE 3004 + +# Creates a non-root user with an explicit UID and adds permission to access the /app folder +# For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers +RUN adduser -u 5678 --disabled-password --gecos "" unstract; \ + chown -R unstract /app; + +USER unstract + +# During debugging, this entry point will be overridden. +# For more information, please refer to https://aka.ms/vscode-docker-python-debug +CMD [".venv/bin/gunicorn", "--bind", "0.0.0.0:3004", "--timeout", "300", "run:app"] diff --git a/docker/dockerfiles/x2text.Dockerfile.dockerignore b/docker/dockerfiles/x2text.Dockerfile.dockerignore new file mode 100644 index 000000000..20ca9015b --- /dev/null +++ b/docker/dockerfiles/x2text.Dockerfile.dockerignore @@ -0,0 +1,8 @@ +.dockerignore +.env* +.git/ +.pytest_cache/ +__pycache__/ +.venv/ +.vscode/ +tests/ diff --git a/docker/sample.essentials.env b/docker/sample.essentials.env new file mode 100644 index 000000000..84231722f --- /dev/null +++ b/docker/sample.essentials.env @@ -0,0 +1,15 @@ + +POSTGRES_USER=unstract_dev +POSTGRES_PASSWORD=unstract_pass +POSTGRES_DB=unstract_db + +MINIO_ROOT_USER=minio +MINIO_ROOT_PASSWORD=minio123 +MINIO_ACCESS_KEY=minio +MINIO_SECRET_KEY=minio123 + +FLIPT_DB_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?sslmode=disable" + +QDRANT_USER=unstract_vector_dev +QDRANT_PASS=unstract_vector_pass +QDRANT_DB=unstract_vector_db diff --git a/docker/sample.proxy_overrides.yaml b/docker/sample.proxy_overrides.yaml new file mode 100644 index 000000000..1cc16cc93 --- /dev/null +++ b/docker/sample.proxy_overrides.yaml @@ -0,0 +1,22 @@ +http: + routers: + frontend: + service: frontend + rule: Host(`frontend.unstract.localhost`) + backend: + service: backend + rule: Host(`frontend.unstract.localhost`) && PathPrefix(`/api/v1`, `/deployment`) + + services: + frontend: + loadBalancer: + servers: + # Point to service running on docker host. + - url: http://host.docker.internal:3000/ + passHostHeader: true + backend: + loadBalancer: + servers: + # Point to service running on docker host. + - url: http://host.docker.internal:8000/ + passHostHeader: true diff --git a/docker/scripts/check_container_exited.sh b/docker/scripts/check_container_exited.sh new file mode 100755 index 000000000..d621dbb1a --- /dev/null +++ b/docker/scripts/check_container_exited.sh @@ -0,0 +1,7 @@ +#! /bin/bash + +export VERSION=test +if [ "$(docker compose -f ../docker-compose.yaml ps -a --filter status=exited | wc -l)" -gt 1 ]; then + echo "There are exited containers." + exit 1 +fi diff --git a/docker/scripts/deploy.sh b/docker/scripts/deploy.sh new file mode 100755 index 000000000..c23663277 --- /dev/null +++ b/docker/scripts/deploy.sh @@ -0,0 +1,145 @@ +#!/bin/bash + +display_help() { + echo "Usage: $0 [options]" + echo "Options:" + echo " -h, --help Display this help message" + echo " -v, --version Version tag for built Docker images (default \"dev\")" + echo " Ignored if --no-build is specified" + echo " -E, --no-setup-env Do not setup env" + echo " -B, --no-build Do not build Docker images" + echo " -l, --local Deploy in local instead of a Docker container" + echo " Requires --services (accepts only one service)" + echo " -s, --services Deploys the specified services only" + echo " Expects service names as a comma separated list" + echo " -V, --verbose Print verbose logs" +} + +debug() { + if [ "$opt_verbose" = true ]; then + echo $1 + fi +} + +log() { + echo $1 +} + +parse_args() { + while [[ $# -gt 0 ]]; do + arg="$1" + case $arg in + -h|--help) + display_help + exit 0 + ;; + -v|--version) + opt_version="$2" + shift + ;; + -E|--no-setup-env) + opt_no_setup_env=true + ;; + -l|--local) + opt_local=true + ;; + -s|--services) + opt_services="$2" + shift + ;; + -V|--verbose) + opt_verbose=true + ;; + *) + echo "Unknown option: $arg" + display_help + exit 1 + ;; + esac + shift + done + + debug "OPTION version: $opt_version" + debug "OPTION no_setup_env: $opt_no_setup_env" + debug "OPTION local: $opt_local" + debug "OPTION services: $opt_services" + debug "OPTION verbose: $opt_verbose" +} + +check_system_requirements() { + system_requirements=("git" "docker") + for sr in "${system_requirements[@]}"; do + command -v $sr >/dev/null 2>&1 || { echo >&2 "$sr is not installed. Exiting."; exit 1; } + done +} + +_deploy_selected_services() { + debug "Deploying selected services" + + script_dir=$(dirname "$(readlink -f "$BASH_SOURCE")") + project_dir="${script_dir}/../.." + IFS=',' read -r -a deploy_services <<< "$opt_services" + + not_services=("docker" "document_display_service" "tools" "unstract") + + debug "Services to deploy: ${deploy_services[@]}" + debug "Not services list: ${not_services[@]}" + + for service_path in "$project_dir"/*; do + if [ ! -d "$service_path" ]; then + continue + fi + + service="$(basename "$service_path")" + + # Check if path is included in not services list. + if [[ $(echo ${not_services[@]} | grep -F -w $service) ]] + then + debug "Not a service, skipping: $service" + continue + fi + + if [ "${#deploy_services[@]}" -gt 0 ] && + ! [[ $(echo ${deploy_services[@]} | grep -F -w $service) ]] + then + debug "Service not opted for deploy: $service" + continue + fi + + log "Deploying service: $service" + done +} + +_setup_env_all_services() { + debug "Setting up env for all services" +} + +_build_all_services() { + debug "Building all services" + VERSION=$opt_version docker compose -f docker-compose.build.yaml build +} + +_deploy_all_services() { + debug "Deploying all services" + VERSION=$opt_version docker compose -f docker-compose.yaml up -d +} + +deploy_services() { + if [ -n "$opt_services" ]; then + _deploy_selected_services + else + _setup_env_all_services + _build_all_services + _deploy_all_services + fi +} + +opt_version="dev" +opt_no_setup_env=false +opt_local=false +opt_services="" +opt_verbose=false + +parse_args "$@" +check_system_requirements +deploy_services diff --git a/docker/scripts/resolve_container_svc_from_host.sh b/docker/scripts/resolve_container_svc_from_host.sh new file mode 100755 index 000000000..0cf1d88a2 --- /dev/null +++ b/docker/scripts/resolve_container_svc_from_host.sh @@ -0,0 +1,110 @@ +#! /bin/bash + +# Inspect Unstract Docker network and add/remove container services +# found to/from local DNS hosts file. +# +# Usage: +# resolve_container_svc_from_host.sh enable|disable +# +# TODO +# Listen for docker events and automatically update local DNS hosts file. +# +DOCKER_NETWORK=unstract-network +LOCAL_DNS_HOSTS_FILE=/etc/hosts +RECORDS_BEGINNING_MARKER="# DO NOT EDIT -- Unstract containers -- BEGIN" +RECORDS_END_MARKER="# DO NOT EDIT -- Unstract containers -- END" + +if [[ "$EUID" -ne 0 ]]; then + echo "Please run with sudo. Exiting." + exit 1 +fi +if ! command -v docker &> /dev/null +then + echo "docker is not installed. Exiting." + exit 2 +fi +if ! command -v jq &> /dev/null +then + echo "jq is not installed. Exiting." + exit 2 +fi + +cmd=$1 +case $cmd in + "enable") + echo "Adding container service IPs to $LOCAL_DNS_HOSTS_FILE..." + + grep -Fxq "$RECORDS_BEGINNING_MARKER" $LOCAL_DNS_HOSTS_FILE + if [ $? -eq 0 ]; then + echo "Container service IPs already present. Exiting." + exit 3 + fi + grep -Fxq "$RECORDS_END_MARKER" $LOCAL_DNS_HOSTS_FILE + if [ $? -eq 0 ]; then + echo "Container service IPs already present. Exiting." + exit 3 + fi + + network=`docker inspect $DOCKER_NETWORK` + if [ $? -ne 0 ]; then + echo "Please run 'docker compose -f docker-compose.yaml up -d' first." + exit 4 + fi + + records="$RECORDS_BEGINNING_MARKER\n" + records_str=$(echo $network | jq -r '.[0].Containers[] | "\(.IPv4Address | split("/")[0]) \(.Name),"') + IFS=',' readarray -t records_arr <<<"$records_str" + for record in "${records_arr[@]}" + do + #TODO Preserve exact middle whitespaces from jq output. + r=$(echo $record | tr -d ,) + records+="${r}\n" + done + records+="$RECORDS_END_MARKER" + + echo -e $records >> $LOCAL_DNS_HOSTS_FILE + + echo "Done." + echo "" + echo "## " + echo "## IMPORTANT!" + echo "## For each docker compose up/down, the container IPs can change." + echo "## Please run this script again to correctly resolve new container" + echo "## services IPs from docker host." + echo "## " + ;; + + "disable") + echo "Removing container service IPs from $LOCAL_DNS_HOSTS_FILE..." + + grep -Fxq "$RECORDS_BEGINNING_MARKER" $LOCAL_DNS_HOSTS_FILE + if [ $? -ne 0 ]; then + echo "Container service IPs not found. Exiting." + exit 3 + fi + grep -Fxq "$RECORDS_END_MARKER" $LOCAL_DNS_HOSTS_FILE + if [ $? -ne 0 ]; then + echo "Container service IPs not found. Exiting." + exit 3 + fi + + t=$(date +%s) + beg_line_no=`awk "/$RECORDS_BEGINNING_MARKER/{ print NR; exit }" $LOCAL_DNS_HOSTS_FILE` + end_line_no=`awk "/$RECORDS_END_MARKER/{ print NR; exit }" $LOCAL_DNS_HOSTS_FILE` + + echo "Backing up $LOCAL_DNS_HOSTS_FILE to $LOCAL_DNS_HOSTS_FILE.bak.$t." + + if [ "$(uname)" == "Darwin" ]; then + sed -i.bak.$t '' -e "${beg_line_no},${end_line_no}d" $LOCAL_DNS_HOSTS_FILE + else + sed -i.bak.$t -e "${beg_line_no},${end_line_no}d" $LOCAL_DNS_HOSTS_FILE + fi + + echo "Done." + ;; + + *) + echo "Usage:" + echo " $0 enable|disable" + ;; +esac diff --git a/document-service/.gitignore b/document-service/.gitignore new file mode 100644 index 000000000..4b3ab3003 --- /dev/null +++ b/document-service/.gitignore @@ -0,0 +1,162 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# 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/ diff --git a/document-service/README.md b/document-service/README.md new file mode 100644 index 000000000..89de1833e --- /dev/null +++ b/document-service/README.md @@ -0,0 +1,72 @@ +## Document Processor Server + +A flask server with the following functionalities: + +* Upload a document to the server +* Perform find and replace on the document + +### Pre-requisites + +#### LibreOffice + +Application Should be installed and running in headless mode + +```bash +/Applications/LibreOffice.app/Contents/MacOS/soffice --backtrace --headless --nocrashreport --nodefault --nologo --nofirststartwizard --norestore --accept="socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;StarOffice.ComponentContext" +``` + +_Change the application path to suit your requirement. The example is for MacOS_ + +#### Unoserver + +Should be installed on the server. Note that Unoserver installation is not straighforward. Unoserver requires the Python +distribution which is bundled with LibreOffice. The following command can be used to install Unoserver + +```bash +/Applications/LibreOffice.app/Contents/Resources/python -m pip install unoserver +``` + +_Change the application path to suit your requirement. The example is for MacOS. Refer +to + +### Environment Variables + +```bash +REDIS_HOST=redis-15866.c99.us-east-1-4.ec2.cloud.redislabs.com +REDIS_PORT=15866 +REDIS_PASSWORD=XXXXXXXXXXXXXXXXXXX +UPLOAD_FOLDER=/tmp/document_service/uploads +PROCESS_FOLDER=/tmp/document_service/processed +LIBREOFFICE_PYTHON=/Applications/LibreOffice.app/Contents/Resources/python +PORT=3000 +MAX_FILE_SIZE=31457280 +``` + +### Run in development + +``` +flask --app "src.unstract.document_service.main:app" run --debug +``` + +### Nginx Configuration + +If we are using Nginx to frontend the server for SSL, make sure `Autherization` and `Content-Length` headers are passed + +```nginx +location / { + proxy_pass http://localhost:3000/; + proxy_buffering off; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + proxy_pass_request_headers on; + client_max_body_size 100M; + proxy_request_buffering off; + include proxy_params; +} +``` + +Thunder collection `thunder-collection_document-service.json` for API testing. `upload` a pdf document, then hit `find_and_replace` api. +it will generate a pdf document. download it and verify replacement text. + +VS Marketplace Link: diff --git a/document-service/pdm.lock b/document-service/pdm.lock new file mode 100644 index 000000000..e534112a7 --- /dev/null +++ b/document-service/pdm.lock @@ -0,0 +1,335 @@ +# This file is @generated by PDM. +# It is not intended for manual editing. + +[metadata] +groups = ["default", "test", "deploy"] +strategy = ["cross_platform"] +lock_version = "4.4.1" +content_hash = "sha256:c7a919b5ac607ed4c72332003ae617935d816e18d6f493884a6bde6297264826" + +[[package]] +name = "async-timeout" +version = "4.0.3" +requires_python = ">=3.7" +summary = "Timeout context manager for asyncio programs" +files = [ + {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, + {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, +] + +[[package]] +name = "blinker" +version = "1.7.0" +requires_python = ">=3.8" +summary = "Fast, simple object-to-object and broadcast signaling" +files = [ + {file = "blinker-1.7.0-py3-none-any.whl", hash = "sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9"}, + {file = "blinker-1.7.0.tar.gz", hash = "sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182"}, +] + +[[package]] +name = "click" +version = "8.1.7" +requires_python = ">=3.7" +summary = "Composable command line interface toolkit" +dependencies = [ + "colorama; platform_system == \"Windows\"", +] +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." +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 = "defusedxml" +version = "0.7.1" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +summary = "XML bomb protection for Python stdlib modules" +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.0" +requires_python = ">=3.7" +summary = "Backport of PEP 654 (exception groups)" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[[package]] +name = "flask" +version = "2.3.2" +requires_python = ">=3.8" +summary = "A simple framework for building complex web applications." +dependencies = [ + "Jinja2>=3.1.2", + "Werkzeug>=2.3.3", + "blinker>=1.6.2", + "click>=8.1.3", + "importlib-metadata>=3.6.0; python_version < \"3.10\"", + "itsdangerous>=2.1.2", +] +files = [ + {file = "Flask-2.3.2-py3-none-any.whl", hash = "sha256:77fd4e1249d8c9923de34907236b747ced06e5467ecac1a7bb7115ae0e9670b0"}, + {file = "Flask-2.3.2.tar.gz", hash = "sha256:8c2f9abd47a9e8df7f0c3f091ce9497d011dc3b31effcf4c85a6e2b50f4114ef"}, +] + +[[package]] +name = "gunicorn" +version = "21.2.0" +requires_python = ">=3.5" +summary = "WSGI HTTP Server for UNIX" +dependencies = [ + "packaging", +] +files = [ + {file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"}, + {file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"}, +] + +[[package]] +name = "importlib-metadata" +version = "7.0.1" +requires_python = ">=3.8" +summary = "Read metadata from Python packages" +dependencies = [ + "zipp>=0.5", +] +files = [ + {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, + {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +requires_python = ">=3.7" +summary = "brain-dead simple config-ini parsing" +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 = "itsdangerous" +version = "2.1.2" +requires_python = ">=3.7" +summary = "Safely pass data to untrusted environments and back." +files = [ + {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, + {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, +] + +[[package]] +name = "jinja2" +version = "3.1.3" +requires_python = ">=3.7" +summary = "A very fast and expressive template engine." +dependencies = [ + "MarkupSafe>=2.0", +] +files = [ + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, +] + +[[package]] +name = "markupsafe" +version = "2.1.5" +requires_python = ">=3.7" +summary = "Safely add untrusted strings to HTML/XML markup." +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-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 = "odfpy" +version = "1.4.1" +summary = "Python API and tools to manipulate OpenDocument files" +dependencies = [ + "defusedxml", +] +files = [ + {file = "odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec"}, +] + +[[package]] +name = "packaging" +version = "23.2" +requires_python = ">=3.7" +summary = "Core utilities for Python packages" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pluggy" +version = "1.4.0" +requires_python = ">=3.8" +summary = "plugin and hook calling mechanisms for python" +files = [ + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, +] + +[[package]] +name = "pytest" +version = "8.0.1" +requires_python = ">=3.8" +summary = "pytest: simple powerful testing with Python" +dependencies = [ + "colorama; sys_platform == \"win32\"", + "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", + "iniconfig", + "packaging", + "pluggy<2.0,>=1.3.0", + "tomli>=1.0.0; python_version < \"3.11\"", +] +files = [ + {file = "pytest-8.0.1-py3-none-any.whl", hash = "sha256:3e4f16fe1c0a9dc9d9389161c127c3edc5d810c38d6793042fb81d9f48a59fca"}, + {file = "pytest-8.0.1.tar.gz", hash = "sha256:267f6563751877d772019b13aacbe4e860d73fe8f651f28112e9ac37de7513ae"}, +] + +[[package]] +name = "python-dotenv" +version = "1.0.1" +requires_python = ">=3.8" +summary = "Read key-value pairs from a .env file and set them as environment variables" +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]] +name = "redis" +version = "4.5.5" +requires_python = ">=3.7" +summary = "Python client for Redis database and key-value store" +dependencies = [ + "async-timeout>=4.0.2; python_full_version <= \"3.11.2\"", +] +files = [ + {file = "redis-4.5.5-py3-none-any.whl", hash = "sha256:77929bc7f5dab9adf3acba2d3bb7d7658f1e0c2f1cafe7eb36434e751c471119"}, + {file = "redis-4.5.5.tar.gz", hash = "sha256:dc87a0bdef6c8bfe1ef1e1c40be7034390c2ae02d92dcd0c7ca1729443899880"}, +] + +[[package]] +name = "setuptools" +version = "69.1.0" +requires_python = ">=3.8" +summary = "Easily download, build, install, upgrade, and uninstall Python packages" +files = [ + {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, + {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +requires_python = ">=3.7" +summary = "A lil' TOML parser" +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 = "unoserver" +version = "1.5" +requires_python = ">=3.7" +summary = "A server for file conversions with Libre Office" +dependencies = [ + "setuptools", +] +files = [ + {file = "unoserver-1.5-py3-none-any.whl", hash = "sha256:2c45f96ba8da8a56b61edb66df679f49fd234cdd58202ec1ec984f7fc74ead1f"}, + {file = "unoserver-1.5.tar.gz", hash = "sha256:af3dedc5fd12bbf1d54d715b5e3bcd0bf0b6adcc1bd0317f3163a02303c5716b"}, +] + +[[package]] +name = "waitress" +version = "2.1.2" +requires_python = ">=3.7.0" +summary = "Waitress WSGI server" +files = [ + {file = "waitress-2.1.2-py3-none-any.whl", hash = "sha256:7500c9625927c8ec60f54377d590f67b30c8e70ef4b8894214ac6e4cad233d2a"}, + {file = "waitress-2.1.2.tar.gz", hash = "sha256:780a4082c5fbc0fde6a2fcfe5e26e6efc1e8f425730863c04085769781f51eba"}, +] + +[[package]] +name = "werkzeug" +version = "3.0.1" +requires_python = ">=3.8" +summary = "The comprehensive WSGI web application library." +dependencies = [ + "MarkupSafe>=2.1.1", +] +files = [ + {file = "werkzeug-3.0.1-py3-none-any.whl", hash = "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10"}, + {file = "werkzeug-3.0.1.tar.gz", hash = "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc"}, +] + +[[package]] +name = "zipp" +version = "3.17.0" +requires_python = ">=3.8" +summary = "Backport of pathlib-compatible object wrapper for zip files" +files = [ + {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, + {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, +] diff --git a/document-service/pyproject.toml b/document-service/pyproject.toml new file mode 100644 index 000000000..cd900f0bd --- /dev/null +++ b/document-service/pyproject.toml @@ -0,0 +1,34 @@ +[project] +name = "unstract-document-service" +version = "0.1.0" +description = "Document processing service" +authors = [ + {name = "Zipstack", email = "devsupport@zipstack.com"}, +] +dependencies = [ + "flask==2.3.2", + "waitress==2.1.2", + "odfpy>=1.4.1", + "unoserver==1.5", + "redis==4.5.5", + "python-dotenv>=1.0.0", +] +requires-python = ">=3.9" +readme = "README.md" +license = {text = "MIT"} + +[build-system] +requires = ["pdm-backend"] +build-backend = "pdm.backend" + +[tool.pdm.build] +includes = ["src"] +package-dir = "src" + +[tool.pdm.dev-dependencies] +test = [ + "pytest>=8.0.1", +] +deploy = [ + "gunicorn>=21.2.0", +] diff --git a/document-service/sample.env b/document-service/sample.env new file mode 100644 index 000000000..52bdae823 --- /dev/null +++ b/document-service/sample.env @@ -0,0 +1,12 @@ +SERVICE_API_TOKEN="" +UPLOAD_FOLDER="/app/uploads" +PROCESS_FOLDER="/app/processed" +LIBREOFFICE_PYTHON="/usr/bin/python3" +MAX_FILE_SIZE=31457280 + + +#Redis +REDIS_HOST="unstract-redis" +REDIS_PORT=6379 +REDIS_PASSWORD="" +REDIS_USER=default diff --git a/document-service/src/unstract/document_service/__init__.py b/document-service/src/unstract/document_service/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/document-service/src/unstract/document_service/main.py b/document-service/src/unstract/document_service/main.py new file mode 100644 index 000000000..764e9cf5f --- /dev/null +++ b/document-service/src/unstract/document_service/main.py @@ -0,0 +1,218 @@ +# type: ignore +import logging +import os +import subprocess +import time +from typing import Any + +import redis +from flask import Flask, request, send_file +from odf import teletype, text +from odf.opendocument import load + +logging.basicConfig( + level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s : %(message)s" +) + +UPLOAD_FOLDER = os.environ.get("UPLOAD_FOLDER", "/tmp/document_service/upload") +PROCESS_FOLDER = os.environ.get("PROCESS_FOLDER", "/tmp/document_service/process") +LIBREOFFICE_PYTHON = os.environ.get("LIBREOFFICE_PYTHON", "/usr/bin/python3") +MAX_FILE_SIZE = int(os.environ.get("MAX_FILE_SIZE", 10485760)) # 10 * 1024 * 1024 +SERVICE_API_TOKEN = os.environ.get("SERVICE_API_TOKEN", "") + +app = Flask("document_service") +app.config["WTF_CSRF_ENABLED"] = False # Sensitive + + +def authentication_middleware(func: Any) -> Any: + def wrapper(*args, **kwargs): + bearer_token = request.headers.get("Authorization") + + # Check if bearer token exists and validate it + if not bearer_token or not validate_bearer_token(bearer_token): + return "Unauthorized", 401 + + return func(*args, **kwargs) + + return wrapper + + +def allowed_file_size(file: Any) -> bool: + return file.content_length <= MAX_FILE_SIZE + + +def validate_bearer_token(token: Any) -> bool: + key_status = None + if token == SERVICE_API_TOKEN: + key_status = True + else: + app.logger.error(f"Error while validating bearer token: {token}") + key_status = False + return key_status + + +@app.route("/health", methods=["GET"], endpoint="health_check") +def health_check(): + return "OK" + + +@app.route("/upload", methods=["POST"], endpoint="upload_file") +@authentication_middleware +def upload_file(): + """ + Sample Usage: + curl -X POST -H "Authorization: 0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + -F "file=@/Users/arun/Devel/pandora_storage/train_ticket.pdf" \ + http://localhost:3000/upload?file_name=file1.pdf&account_id=1234 + """ + + if "file" not in request.files: + app.logger.error("No file found!") + return "No file found!", 400 + + _file = request.files["file"] + if _file.filename == "": + app.logger.error("No selected file!") + return "No selected file!", 400 + + # Check file size + content_length = request.headers.get("Content-Length", type=int) + if content_length is not None and content_length > MAX_FILE_SIZE: + app.logger.error( + f"File size exceeds the limit! {content_length} > {MAX_FILE_SIZE}" + ) + return "File size exceeds the limit!", 400 + + account_id = request.args.get("account_id") + file_name = request.args.get("file_name") + app.logger.info(f"Uploading file {file_name} for account {account_id}") + + try: + file_path = os.path.join(UPLOAD_FOLDER, f"{account_id}_{file_name}") + _file.save(file_path) + except Exception as e: + app.logger.error(f"Error while saving file: {e}") + return "Error while saving file!", 500 + + try: + # Store upload time in redis + redis_host = os.environ.get("REDIS_HOST") + redis_port = int(os.environ.get("REDIS_PORT")) + redis_password = os.environ.get("REDIS_PASSWORD") + r = redis.Redis(host=redis_host, port=redis_port, password=redis_password) + # TODO: Create a file reaper process to look at uploaded time and delete + redis_key = f"upload_time:{account_id}_{file_name}" + current_timestamp = int(time.time()) + r.set(redis_key, current_timestamp) + r.close() + except Exception as e: + app.logger.error(f"Error while storing upload time in redis: {e}") + if os.path.exists(file_path): + os.remove(file_path) + return "Error while storing upload time in redis!", 500 + + app.logger.info(f"File uploaded successfully! {file_path}") + return "File uploaded successfully!", 200 + + +@app.route("/find_and_replace", methods=["POST"], endpoint="find_and_replace") +@authentication_middleware +def find_and_replace(): + account_id = request.args.get("account_id") + file_name = request.args.get("file_name") + output_format = request.args.get("output_format").lower() + find_and_replace_text = request.json + + app.logger.info(f"Find and replace for file {file_name} for account {account_id}") + app.logger.info(f"Output format: {output_format}") + + if output_format not in ["pdf"]: + app.logger.error(f"Unsupported output format: {output_format}") + return "Unsupported output format!", 400 + + file_namex = os.path.join(UPLOAD_FOLDER, f"{account_id}_{file_name}") + + # Check if file exists + if not os.path.exists(file_namex): + app.logger.error(f"File not found! {file_namex}") + return "File not found!", 400 + + # Convert the orginal file to ODT format for processing + file_name_odt = f"{account_id}_{file_name}.odt" + file_name_odt = os.path.join(PROCESS_FOLDER, file_name_odt) + try: + command = f"{LIBREOFFICE_PYTHON} -m unoserver.converter --convert-to odt \ + --filter writer8 {file_namex} {file_name_odt}" + result = subprocess.run(command, shell=True, capture_output=True, text=True) + app.logger.info(result) + if result.returncode != 0: + app.logger.error( + f"Failed to convert file to ODT format: \ + {result.stdout} | ERR: {result.stderr}" + ) + return "Failed to convert file to ODT format!", 500 + else: + app.logger.info( + f"File converted to ODT format successfully! {file_name_odt}" + ) + app.logger.info(f"ODT convertion result: {result.stdout} | {result.stderr}") + except Exception as e: + app.logger.error(f"Error while converting file to ODT format: {e}") + return "Error while converting file to ODT format!", 500 + + # Find and replace + doc = load(file_name_odt) + for find_str in find_and_replace_text: + app.logger.info( + f"Find and replace: {find_str} -> {find_and_replace_text[find_str]}" + ) + replace_str = find_and_replace_text[find_str] + for element in doc.getElementsByType(text.Span): + if find_str in teletype.extractText(element): + app.logger.info(f"Found {find_str} in {teletype.extractText(element)}") + new_element = text.Span() + new_element.setAttribute("stylename", element.getAttribute("stylename")) + t = teletype.extractText(element) + t = t.replace(find_str, replace_str) + new_element.addText(t) + element.parentNode.insertBefore(new_element, element) + element.parentNode.removeChild(element) + doc.save(file_name_odt) + + file_name_output = f"{account_id}_{file_name}.{output_format}" + file_name_output = os.path.join(PROCESS_FOLDER, file_name_output) + + # Convert the ODT file to the requested format + try: + command = ( + f"{LIBREOFFICE_PYTHON} -m unoserver.converter --convert-to pdf " + f"--filter writer_pdf_Export {file_name_odt} {file_name_output}" + ) + result = subprocess.run(command, shell=True, capture_output=True, text=True) + if result.returncode != 0: + app.logger.error( + f"Failed to convert file to {output_format} format: " + f"{result.stdout} | ERR: {result.stderr}" + ) + return "Failed to convert file to ODT format!", 500 + else: + app.logger.info( + f"File converted to {output_format} format successfully! " + f"{file_name_output}" + ) + app.logger.info(f"ODT convertion result: {result.stdout} | {result.stderr}") + except Exception as e: + app.logger.error(f"Error while converting file to {output_format} format: {e}") + return f"Error while converting file to {output_format} format!", 500 + return send_file(file_name_output, as_attachment=True) + + +if __name__ == "__main__": + # Check if upload folder exists and create it if not + if not os.path.exists(UPLOAD_FOLDER): + os.makedirs(UPLOAD_FOLDER) + if not os.path.exists(PROCESS_FOLDER): + os.makedirs(PROCESS_FOLDER) + + # Start the server + app.run() diff --git a/document-service/tests/__init__.py b/document-service/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/document-service/thunder-collection_document-service.json b/document-service/thunder-collection_document-service.json new file mode 100644 index 000000000..443f60502 --- /dev/null +++ b/document-service/thunder-collection_document-service.json @@ -0,0 +1,97 @@ +{ + "client": "Thunder Client", + "collectionName": "document-service", + "dateExported": "2023-08-15T03:42:29.575Z", + "version": "1.1", + "folders": [], + "requests": [ + { + "_id": "54e80168-0fbf-4de6-8397-4069ff0bcb0d", + "colId": "a50995ac-f753-4b4c-847e-fc03d134641c", + "containerId": "", + "name": "upload", + "url": "/upload?file_name=test.pdf&account_id=1234", + "method": "POST", + "sortNum": 10000, + "created": "2023-08-14T09:58:13.352Z", + "modified": "2023-08-14T16:58:48.550Z", + "headers": [ + { + "name": "Authorization", + "value": "builtin_functions_key:123", + "isDisabled": true + } + ], + "params": [ + { + "name": "file_name", + "value": "test.pdf", + "isPath": false + }, + { + "name": "account_id", + "value": "1234", + "isPath": false + } + ], + "body": { + "type": "formdata", + "raw": "", + "form": [], + "files": [ + { + "name": "file", + "value": "/Users/path_to_file/test.pdf" + } + ] + }, + "tests": [] + }, + { + "_id": "e5d544ac-1500-4ea8-a9cd-22583be4c86f", + "colId": "a50995ac-f753-4b4c-847e-fc03d134641c", + "containerId": "", + "name": "find_and_replace", + "url": "/find_and_replace?account_id=1234&file_name=test.pdf&output_format=pdf", + "method": "POST", + "sortNum": 20000, + "created": "2023-08-14T17:00:10.866Z", + "modified": "2023-08-14T17:05:05.746Z", + "headers": [], + "params": [ + { + "name": "account_id", + "value": "1234", + "isPath": false + }, + { + "name": "file_name", + "value": "test.pdf", + "isPath": false + }, + { + "name": "output_format", + "value": "pdf", + "isPath": false + } + ], + "body": { + "type": "json", + "raw": "{\n \"Slack\": \"Jaseem\"\n}", + "form": [] + }, + "tests": [] + } + ], + "settings": { + "headers": [ + { + "name": "Authorization", + "value": "123" + } + ], + "options": { + "baseUrl": "http://localhost:3000" + } + } +} diff --git a/document-service/wrapper.sh b/document-service/wrapper.sh new file mode 100755 index 000000000..1bfa6e0fb --- /dev/null +++ b/document-service/wrapper.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Start the first process +# Args: --nocrashreport --nodefault +/usr/bin/libreoffice --headless --nologo --nofirststartwizard --norestore --accept="socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;StarOffice.ComponentContext" & + +# Start the second process +# 'src' layout is detected from pdm settings in pyproject.toml +.venv/bin/gunicorn --bind 0.0.0.0:3002 --timeout 300 unstract.document_service.main:app & + +# Wait for any process to exit +wait -n + +# Exit with status of process that exited first +exit $? diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json new file mode 100644 index 000000000..61634af50 --- /dev/null +++ b/frontend/.eslintrc.json @@ -0,0 +1,69 @@ +{ + "env": { + "browser": true, + "es2022": true, + "node": true, + "jest": true + }, + "extends": [ + "eslint:recommended", + "plugin:react/recommended", + "google", + "prettier", + "plugin:prettier/recommended" + ], + "parserOptions": { + "ecmaFeatures": { + "jsx": true + }, + "ecmaVersion": "latest", + "sourceType": "module", + "parser": "babel-eslint" + }, + "plugins": ["react", "import"], + "rules": { + "react/react-in-jsx-scope": 0, + "react/jsx-uses-react": 0, + "require-jsdoc": 0, + "array-callback-return": [2], + "no-mixed-operators": [2], + "eqeqeq": [2], + "func-names": "warn", + "import/no-unresolved": [1, { "caseSensitive": false }], + "import/order": [ + "warn", + { + "groups": ["builtin", "external", "internal"], + "pathGroups": [ + { + "pattern": "react", + "group": "external", + "position": "before" + }, + { + "pattern": "*.json", + "group": "index", + "patternOptions": { "matchBase": true }, + "position": "after" + }, + { + "pattern": "*.css", + "group": "index", + "patternOptions": { "matchBase": true }, + "position": "after" + } + ], + "newlines-between": "always" + } + ] + }, + "settings": { + "react": { + "version": "detect" + } + }, + "ignorePatterns": [ + "node_modules", + "build" + ] +} diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 000000000..f287e6415 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,24 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 000000000..2f4fd022b --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,127 @@ +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Steps to setup the frontend in local + +### Requirements + +NodeJS 16 + +1. Clone this repo in your local by the following command: + `git clone https://github.com/Zipstack/Pandora.git` + +2. Now in terminal navigate to this path `Pandora/frontend` and run the following commands: + `npm install` + +### Steps to run the setup + + `npm start` + +3. Node will automatically run the `localhost:3000` in your browser. + The page will reload when you make changes. + You may also see any lint errors in the console. + +## Notes + +1. Install the Prettier extension in your VSCode editor +2. Install the ESLint extension in your VSCode editor + +## Available Scripts + +In the project directory, you can run: + +### `npm start` + +Runs the app in the development mode.\ +Open [http://localhost:3000](http://localhost:3000) to view it in your browser. + +The page will reload when you make changes.\ +You may also see any lint errors in the console. + +### `npm test` + +Launches the test runner in the interactive watch mode.\ +See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `npm run build` + +Builds the app for production to the `build` folder.\ +It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.\ +Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `npm run eject` + +**Note: this is a one-way operation. Once you `eject`, you can't go back!** + +If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. + +You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). + +### Code Splitting + +This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) + +### Analyzing the Bundle Size + +This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) + +### Making a Progressive Web App + +This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) + +### Advanced Configuration + +This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) + +### Deployment + +This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) + +### `npm run build` fails to minify + +This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) + +## Dockerization + +Dockerizing a project bootstrapped with Create React App (CRA) is a common practice to ensure consistent development and deployment environments. Docker containers provide isolation and portability, making it easier to manage your application's dependencies and run it consistently across different environments. + +### Development + +Create a Dockerfile.dev for development. This Dockerfile will use Node.js to set up your development environment: + +Remember, you need to have your app code and any necessary files in the same directory as this Dockerfile. To build and run the Docker container, you can use the following commands: + +``` +# Build the Docker image +docker build -t frontend:dev -f Dockerfile.dev . + +# Run the Docker container +docker run -it -p 3000:3000 frontend:dev +``` + +## Production + +Create a Dockerfile.prod for production. This Dockerfile will use NGINX to serve your optimized production build: + +``` +npm ci && npm run build + +docker build -t frontend:prod -f Dockerfile.prod . + +docker run -p 80:80 frontend:prod +``` + +If you need a custom NGINX configuration, place it in your project root folder (e.g., nginx.conf) and copy it using the COPY command in Dockerfile.prod. + +This approach allows you to have separate Dockerfiles for development and production while keeping them in the root folder of your React app. It helps you maintain a consistent and organized structure for managing different deployment environments. diff --git a/frontend/nginx.conf b/frontend/nginx.conf new file mode 100644 index 000000000..4edc59d21 --- /dev/null +++ b/frontend/nginx.conf @@ -0,0 +1,53 @@ +# Running as non-root user will trigger warning. +# user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log notice; +# Running as non-root user will trigger warning +# for default /var/run/ prefix. +pid /tmp/nginx.pid; + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + gzip on; + + # Non-root user will not have access to default + # /var/cache/nginx/ prefix. + client_body_temp_path /tmp/client_temp 1 2; + proxy_temp_path /tmp/proxy_temp 1 2; + fastcgi_temp_path /tmp/fastcgi_temp 1 2; + uwsgi_temp_path /tmp/uwsgi_temp 1 2; + scgi_temp_path /tmp/scgi_temp 1 2; + + server { + listen 80; + root /usr/share/nginx/html; + include /etc/nginx/mime.types; + + # If a react app URI is directly accessed we will get 404 + # since there will be no file representing that path. + # Below config will load index.html file in such case and + # browser will load the proper path using JS. + location / { + try_files $uri /index.html; + } + } +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 000000000..76884e3f5 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,34979 @@ +{ + "name": "frontend", + "version": "0.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.1.0", + "dependencies": { + "@ant-design/icons": "^5.1.4", + "@react-pdf-viewer/core": "^3.12.0", + "@react-pdf-viewer/default-layout": "^3.12.0", + "@react-pdf-viewer/page-navigation": "^3.12.0", + "@rjsf/antd": "^5.16.1", + "@rjsf/core": "^5.8.1", + "@rjsf/utils": "^5.8.1", + "@rjsf/validator-ajv8": "^5.8.1", + "@testing-library/jest-dom": "^5.16.5", + "@testing-library/react": "^13.4.0", + "@testing-library/user-event": "^13.5.0", + "antd": "^5.5.1", + "axios": "^1.4.0", + "cron-validator": "^1.3.1", + "handlebars": "^4.7.8", + "http-proxy-middleware": "^2.0.6", + "js-yaml": "^4.1.0", + "markdown-to-jsx": "^7.2.1", + "moment": "^2.29.4", + "pdfjs-dist": "^3.4.120", + "prismjs": "^1.29.0", + "react": "^18.2.0", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", + "react-dom": "^18.2.0", + "react-router-dom": "^6.11.2", + "react-scripts": "5.0.1", + "react-social-login-buttons": "^3.9.1", + "remark-gfm": "^3.0.1", + "socket.io-client": "^4.7.2", + "zustand": "^4.3.8" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "eslint": "^8.41.0", + "eslint-config-google": "^0.14.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.32.2", + "prettier": "^2.8.8", + "prettier-quick": "^0.0.5", + "webpack": "^5.84.0" + }, + "engines": { + "node": ">=16.0.0 <20", + "npm": ">=8.19.4" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz", + "integrity": "sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==" + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@ant-design/colors": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.0.2.tgz", + "integrity": "sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg==", + "dependencies": { + "@ctrl/tinycolor": "^3.6.1" + } + }, + "node_modules/@ant-design/cssinjs": { + "version": "1.18.4", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.18.4.tgz", + "integrity": "sha512-IrUAOj5TYuMG556C9gdbFuOrigyhzhU5ZYpWb3gYTxAwymVqRbvLzFCZg6OsjLBR6GhzcxYF3AhxKmjB+rA2xA==", + "dependencies": { + "@babel/runtime": "^7.11.1", + "@emotion/hash": "^0.8.0", + "@emotion/unitless": "^0.7.5", + "classnames": "^2.3.1", + "csstype": "^3.1.3", + "rc-util": "^5.35.0", + "stylis": "^4.0.13" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@ant-design/icons": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.2.6.tgz", + "integrity": "sha512-4wn0WShF43TrggskBJPRqCD0fcHbzTYjnaoskdiJrVHg86yxoZ8ZUqsXvyn4WUqehRiFKnaclOhqk9w4Ui2KVw==", + "dependencies": { + "@ant-design/colors": "^7.0.0", + "@ant-design/icons-svg": "^4.3.0", + "@babel/runtime": "^7.11.2", + "classnames": "^2.2.6", + "rc-util": "^5.31.1" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@ant-design/icons-svg": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.3.1.tgz", + "integrity": "sha512-4QBZg8ccyC6LPIRii7A0bZUk3+lEDCLnhB+FVsflGdcWPPmV+j3fire4AwwoqHV/BibgvBmR9ZIo4s867smv+g==" + }, + "node_modules/@ant-design/react-slick": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-1.0.2.tgz", + "integrity": "sha512-Wj8onxL/T8KQLFFiCA4t8eIRGpRR+UPgOdac2sYzonv+i0n3kXHmvHLLiOYL655DQx2Umii9Y9nNgL7ssu5haQ==", + "dependencies": { + "@babel/runtime": "^7.10.4", + "classnames": "^2.2.5", + "json2mq": "^0.2.0", + "resize-observer-polyfill": "^1.5.1", + "throttle-debounce": "^5.0.0" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, + "node_modules/@apideck/better-ajv-errors": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", + "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", + "dependencies": { + "json-schema": "^0.4.0", + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "dependencies": { + "@babel/highlight": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz", + "integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", + "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helpers": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.22.5.tgz", + "integrity": "sha512-C69RWYNYtrgIRE5CmTd77ZiLDXqgBipahJc/jHP3sLcAGj6AJzxNIuKNpVnICqbyK7X3pFUfEvL++rvtbQpZkQ==", + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.11.0", + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/generator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz", + "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==", + "dependencies": { + "@babel/types": "^7.22.5", + "@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-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz", + "integrity": "sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz", + "integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==", + "dependencies": { + "@babel/compat-data": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.5.tgz", + "integrity": "sha512-xkb58MyOYIslxu3gKmVXmjTtUPvBU4odYzbiIQbWwLKIHCsx6UGZGX6F1IznMFVnDdirseUZopzN+ZRt8Xb33Q==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.5.tgz", + "integrity": "sha512-1VpEFOIbMRaXyDeUwUfmTIxExLwQ+zkW+Bh5zXpApA3oQedBx9v/updixWxnx/bZpKw7u8VxWjb/qWpIcmPq8A==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.0.tgz", + "integrity": "sha512-RnanLx5ETe6aybRi1cO/edaRH+bNYWaryCEmjDDYyNr4wnSzyOp8T0dWipmqVHKEY3AbVKUom50AKSlj1zmKbg==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dependencies": { + "is-core-module": "^2.11.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/@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz", + "integrity": "sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz", + "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.5.tgz", + "integrity": "sha512-cU0Sq1Rf4Z55fgz7haOakIyM7+x/uCFwXpLPaeRzfoUtAEAuUZjZvFPjL/rk5rW693dIgn2hng1W7xbT7lWT4g==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-wrap-function": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.5.tgz", + "integrity": "sha512-aLdNM5I3kdI/V9xGNyKSF3X/gTyMUBohTZ+/3QdQKAA9vxIiy12E+8E2HoOP1/DjeqU+g6as35QHJNMDDYpuCg==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", + "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.5.tgz", + "integrity": "sha512-bYqLIBSEshYcYQyfks8ewYA8S30yaGSeRslcvKMvoUk6HHPySbxHq9YRi6ghhzEU+yhQv9bP/jXnygkStOcqZw==", + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz", + "integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==", + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz", + "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz", + "integrity": "sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz", + "integrity": "sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.22.5.tgz", + "integrity": "sha512-h8hlezQ4dl6ixodgXkH8lUfcD7x+WAuIqPUjwGoItynrXOAv4a4Tci1zA/qjzQjjcl0v3QpLdc2LM6ZACQuY7A==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/plugin-syntax-decorators": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.22.5.tgz", + "integrity": "sha512-avpUOBS7IU6al8MmF1XpAyj9QYeLPuSDJI5D4pVMSMdL7xQokKqJPYQC67RCT0aCTashUXPiGwMJ0DEXXCEmMA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.22.5.tgz", + "integrity": "sha512-9RdCl0i+q0QExayk2nOS7853w08yLucnnPML6EN9S8fgMPVtdLDCdx/cOQ/i44Lb9UeQX9A35yaqBBOMMZxPxQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", + "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz", + "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", + "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", + "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-async-generator-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.5.tgz", + "integrity": "sha512-gGOEvFzm3fWoyD5uZq7vVTD57pPJ3PczPUD/xCFGjzBpUosnklmXyKnGQbbbGs1NPNPskFex0j93yKbHt0cHyg==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", + "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", + "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", + "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-block-scoping": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz", + "integrity": "sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==", + "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-class-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz", + "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz", + "integrity": "sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.5.tgz", + "integrity": "sha512-2edQhLfibpWpsVBx2n/GKOz6JdGQvLruZQfGr9l1qes2KQaWswjBzhQF7UDUZMNaMMQeYnQzxwOMPsbYF7wqPQ==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", + "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz", + "integrity": "sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==", + "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-dotall-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz", + "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz", + "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==", + "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-dynamic-import": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz", + "integrity": "sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz", + "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz", + "integrity": "sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.22.5.tgz", + "integrity": "sha512-tujNbZdxdG0/54g/oua8ISToaXTFBf8EnSb5PgQSciIXWOWKX3S4+JR7ZE9ol8FZwf9kxitzkGQ+QWeov/mCiA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-flow": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz", + "integrity": "sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A==", + "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-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", + "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz", + "integrity": "sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", + "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", + "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-logical-assignment-operators": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz", + "integrity": "sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", + "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", + "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-modules-amd": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz", + "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==", + "dependencies": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz", + "integrity": "sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==", + "dependencies": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz", + "integrity": "sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz", + "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==", + "dependencies": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz", + "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==", + "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-nullish-coalescing-operator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz", + "integrity": "sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz", + "integrity": "sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz", + "integrity": "sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ==", + "dependencies": { + "@babel/compat-data": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", + "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz", + "integrity": "sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.5.tgz", + "integrity": "sha512-AconbMKOMkyG+xCng2JogMCDcqW8wedQAqpVIL4cOSescZ7+iW8utC6YDZLMCSUIReEA733gzRSaOSXMAt/4WQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz", + "integrity": "sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==", + "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-private-methods": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz", + "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz", + "integrity": "sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", + "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", + "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-constant-elements": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.22.5.tgz", + "integrity": "sha512-BF5SXoO+nX3h5OhlN78XbbDrBOffv+AxPP2ENaJOVqjWCgBDeOY3WcaUcddutGSfoap+5NEQ/q/4I3WZIvgkXA==", + "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-display-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz", + "integrity": "sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw==", + "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": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.5.tgz", + "integrity": "sha512-rog5gZaVbUip5iWDMTYbVM15XQq+RkUKhET/IHR6oizR+JEoN6CAfTTuHcK4vwUyzca30qqHqEpzBOnaRMWYMA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.22.5.tgz", + "integrity": "sha512-gP4k85wx09q+brArVinTXhWiyzLl9UpmGva0+mWyKxk6JZequ05x3eUcIUE+FyttPKJFRRVtAvQaJ6YF9h1ZpA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz", + "integrity": "sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz", + "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==", + "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-runtime": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.5.tgz", + "integrity": "sha512-bg4Wxd1FWeFx3daHFTWk1pkSWK/AyQuiyAoeZAOkAOUBjnZPH6KT7eMxouV47tQ6hl6ax2zyAWBdWZXbrvXlaw==", + "dependencies": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.3", + "babel-plugin-polyfill-corejs3": "^0.8.1", + "babel-plugin-polyfill-regenerator": "^0.5.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", + "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", + "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-spread": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", + "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz", + "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==", + "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-template-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", + "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", + "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-typeof-symbol": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz", + "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==", + "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-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.5.tgz", + "integrity": "sha512-SMubA9S7Cb5sGSFFUlqxyClTA9zWJ8qGQrppNUm05LtFuN1ELRFNndkix4zUJrC9F+YivWwa1dHMSyo0e0N9dA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-typescript": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz", + "integrity": "sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==", + "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-unicode-property-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz", + "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz", + "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz", + "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.5.tgz", + "integrity": "sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A==", + "dependencies": { + "@babel/compat-data": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.5", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.5", + "@babel/plugin-transform-async-to-generator": "^7.22.5", + "@babel/plugin-transform-block-scoped-functions": "^7.22.5", + "@babel/plugin-transform-block-scoping": "^7.22.5", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-class-static-block": "^7.22.5", + "@babel/plugin-transform-classes": "^7.22.5", + "@babel/plugin-transform-computed-properties": "^7.22.5", + "@babel/plugin-transform-destructuring": "^7.22.5", + "@babel/plugin-transform-dotall-regex": "^7.22.5", + "@babel/plugin-transform-duplicate-keys": "^7.22.5", + "@babel/plugin-transform-dynamic-import": "^7.22.5", + "@babel/plugin-transform-exponentiation-operator": "^7.22.5", + "@babel/plugin-transform-export-namespace-from": "^7.22.5", + "@babel/plugin-transform-for-of": "^7.22.5", + "@babel/plugin-transform-function-name": "^7.22.5", + "@babel/plugin-transform-json-strings": "^7.22.5", + "@babel/plugin-transform-literals": "^7.22.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.22.5", + "@babel/plugin-transform-member-expression-literals": "^7.22.5", + "@babel/plugin-transform-modules-amd": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.5", + "@babel/plugin-transform-modules-systemjs": "^7.22.5", + "@babel/plugin-transform-modules-umd": "^7.22.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.22.5", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.5", + "@babel/plugin-transform-numeric-separator": "^7.22.5", + "@babel/plugin-transform-object-rest-spread": "^7.22.5", + "@babel/plugin-transform-object-super": "^7.22.5", + "@babel/plugin-transform-optional-catch-binding": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.5", + "@babel/plugin-transform-parameters": "^7.22.5", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.5", + "@babel/plugin-transform-property-literals": "^7.22.5", + "@babel/plugin-transform-regenerator": "^7.22.5", + "@babel/plugin-transform-reserved-words": "^7.22.5", + "@babel/plugin-transform-shorthand-properties": "^7.22.5", + "@babel/plugin-transform-spread": "^7.22.5", + "@babel/plugin-transform-sticky-regex": "^7.22.5", + "@babel/plugin-transform-template-literals": "^7.22.5", + "@babel/plugin-transform-typeof-symbol": "^7.22.5", + "@babel/plugin-transform-unicode-escapes": "^7.22.5", + "@babel/plugin-transform-unicode-property-regex": "^7.22.5", + "@babel/plugin-transform-unicode-regex": "^7.22.5", + "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.3", + "babel-plugin-polyfill-corejs3": "^0.8.1", + "babel-plugin-polyfill-regenerator": "^0.5.0", + "core-js-compat": "^3.30.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.22.5.tgz", + "integrity": "sha512-M+Is3WikOpEJHgR385HbuCITPTaPRaNkibTEa9oiofmJvIsrceb4yp9RL9Kb+TE8LznmeyZqpP+Lopwcx59xPQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-transform-react-display-name": "^7.22.5", + "@babel/plugin-transform-react-jsx": "^7.22.5", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.22.5.tgz", + "integrity": "sha512-YbPaal9LxztSGhmndR46FmAbkJ/1fAsw293tSU+I5E5h+cnJ3d4GTwyUgGYmOXJYdGA+uNePle4qbaRzj2NISQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.5", + "@babel/plugin-transform-typescript": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "node_modules/@babel/runtime": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", + "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime/node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/@babel/template": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz", + "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==", + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", + "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + }, + "node_modules/@csstools/normalize.css": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", + "integrity": "sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==" + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "dependencies": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", + "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.0.10" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "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.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.2", + "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/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/@eslint/js": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz", + "integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/console/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/console/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/console/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/console/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/core": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/core/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/core/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/environment/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/environment/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", + "dependencies": { + "jest-get-type": "^29.4.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "dependencies": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/fake-timers/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/globals/node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/reporters/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "dependencies": { + "@sinclair/typebox": "^0.25.16" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/source-map/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-result/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-result/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "dependencies": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/transform/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/types": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", + "dependencies": { + "@jest/schemas": "^29.4.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "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.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", + "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz", + "integrity": "sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==", + "dependencies": { + "ansi-html-community": "^0.0.8", + "common-path-prefix": "^3.0.0", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "find-up": "^5.0.0", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^3.0.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "@types/webpack": "4.x || 5.x", + "react-refresh": ">=0.10.0 <1.0.0", + "sockjs-client": "^1.4.0", + "type-fest": ">=0.17.0 <4.0.0", + "webpack": ">=4.43.0 <6.0.0", + "webpack-dev-server": "3.x || 4.x", + "webpack-hot-middleware": "2.x", + "webpack-plugin-serve": "0.x || 1.x" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "sockjs-client": { + "optional": true + }, + "type-fest": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + }, + "webpack-hot-middleware": { + "optional": true + }, + "webpack-plugin-serve": { + "optional": true + } + } + }, + "node_modules/@rc-component/color-picker": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-1.5.1.tgz", + "integrity": "sha512-onyAFhWKXuG4P162xE+7IgaJkPkwM94XlOYnQuu69XdXWMfxpeFi6tpJBsieIMV7EnyLV5J3lDzdLiFeK0iEBA==", + "dependencies": { + "@babel/runtime": "^7.23.6", + "@ctrl/tinycolor": "^3.6.1", + "classnames": "^2.2.6", + "rc-util": "^5.38.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/context": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz", + "integrity": "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/mini-decimal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz", + "integrity": "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==", + "dependencies": { + "@babel/runtime": "^7.18.0" + }, + "engines": { + "node": ">=8.x" + } + }, + "node_modules/@rc-component/mutate-observer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz", + "integrity": "sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==", + "dependencies": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/portal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz", + "integrity": "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==", + "dependencies": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/tour": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.12.3.tgz", + "integrity": "sha512-U4mf1FiUxGCwrX4ed8op77Y8VKur+8Y/61ylxtqGbcSoh1EBC7bWd/DkLu0ClTUrKZInqEi1FL7YgFtnT90vHA==", + "dependencies": { + "@babel/runtime": "^7.18.0", + "@rc-component/portal": "^1.0.0-9", + "@rc-component/trigger": "^1.3.6", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/trigger": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-1.18.2.tgz", + "integrity": "sha512-jRLYgFgjLEPq3MvS87fIhcfuywFSRDaDrYw1FLku7Cm4esszvzTbA0JBsyacAyLrK9rF3TiHFcvoEDMzoD3CTA==", + "dependencies": { + "@babel/runtime": "^7.23.2", + "@rc-component/portal": "^1.1.0", + "classnames": "^2.3.2", + "rc-motion": "^2.0.0", + "rc-resize-observer": "^1.3.1", + "rc-util": "^5.38.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@react-dnd/asap": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", + "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==" + }, + "node_modules/@react-dnd/invariant": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz", + "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==" + }, + "node_modules/@react-dnd/shallowequal": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", + "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" + }, + "node_modules/@react-pdf-viewer/attachment": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/attachment/-/attachment-3.12.0.tgz", + "integrity": "sha512-mhwrYJSIpCvHdERpLUotqhMgSjhtF+BTY1Yb9Fnzpcq3gLZP+Twp5Rynq21tCrVdDizPaVY7SKu400GkgdMfZw==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/bookmark": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/bookmark/-/bookmark-3.12.0.tgz", + "integrity": "sha512-i7nEit8vIFMAES8RFGwprZ9cXOOZb9ZStPW6E6yuObJEXcvBj/ctsbBJGZxqUZOGklM0JoB7sjHyxAriHfe92A==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/core": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/core/-/core-3.12.0.tgz", + "integrity": "sha512-8MsdlQJ4jaw3GT+zpCHS33nwnvzpY0ED6DEahZg9WngG++A5RMhk8LSlxdHelwaFFHFiXBjmOaj2Kpxh50VQRg==", + "peerDependencies": { + "pdfjs-dist": "^2.16.105 || ^3.0.279", + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/default-layout": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/default-layout/-/default-layout-3.12.0.tgz", + "integrity": "sha512-K2fS4+TJynHxxCBFuIDiFuAw3nqOh4bkBgtVZ/2pGvnFn9lLg46YGLMnTXCQqtyZzzXYh696jmlFViun3is4pA==", + "dependencies": { + "@react-pdf-viewer/attachment": "3.12.0", + "@react-pdf-viewer/bookmark": "3.12.0", + "@react-pdf-viewer/core": "3.12.0", + "@react-pdf-viewer/thumbnail": "3.12.0", + "@react-pdf-viewer/toolbar": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/full-screen": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/full-screen/-/full-screen-3.12.0.tgz", + "integrity": "sha512-hQouJ26QUaRBCXNMU1aI1zpJn4l4PJRvlHhuE2dZYtLl37ycjl7vBCQYZW1FwnuxMWztZsY47R43DKaZORg0pg==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/get-file": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/get-file/-/get-file-3.12.0.tgz", + "integrity": "sha512-Uhq45n2RWlZ7Ec/BtBJ0WQESRciaYIltveDXHNdWvXgFdOS8XsvB+mnTh/wzm7Cfl9hpPyzfeezifdU9AkQgQg==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/open": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/open/-/open-3.12.0.tgz", + "integrity": "sha512-vhiDEYsiQLxvZkIKT9VPYHZ1BOnv46x9eCEmRWxO1DJ8fa/GRDTA9ivXmq/ap0dGEJs6t+epleCkCEfllLR/Yw==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/page-navigation": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/page-navigation/-/page-navigation-3.12.0.tgz", + "integrity": "sha512-tVEJ48Dd5kajV1nKkrPWijglJRNBiKBTyYDKVexhiRdTHUP1f6QQXiSyDgCUb0IGSZeJzOJb1h7ApKHe8OTtuw==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/print": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/print/-/print-3.12.0.tgz", + "integrity": "sha512-xJn76CgbU/M2iNaN7wLHTg+sdOekkRMfCakFLwPrE+SR7qD6NUF4vQQKJBSVCCK5bUijzb6cWfKGfo8VA72o4Q==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/properties": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/properties/-/properties-3.12.0.tgz", + "integrity": "sha512-dYTCHtVwFNkpDo7QxL2qk/8zAKndLwdD1FFxBftl6jIlQbtvNdxkFfkv1HcQING9Ic+7DBryOiD7W0ze4IERYg==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/rotate": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/rotate/-/rotate-3.12.0.tgz", + "integrity": "sha512-yaxaMYPChvNOjR8+AxRmj0kvojyJKPq4XHEcIB2lJJgBY1Zra3mliDUP3Nlb4yV8BS9+yBqWn9U9mtnopQD+tw==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/scroll-mode": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/scroll-mode/-/scroll-mode-3.12.0.tgz", + "integrity": "sha512-okII7Xqhl6cMvl1izdEvlXNJ+vJVq/qdg53hJIDYVgBCWskLk/cpjUg/ZonBxseG9lIDP3w2VO1McT8Gn11OAg==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/search": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/search/-/search-3.12.0.tgz", + "integrity": "sha512-jAkLpis49fsDDY/HrbUZIOIhzF5vynONQNA4INQKI38r/MjveblrkNv7qbr9j5lQ/WFic5+gD1e+Mtpf1/7DiA==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/selection-mode": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/selection-mode/-/selection-mode-3.12.0.tgz", + "integrity": "sha512-yysWEu2aCtBvzSgbhgI9kT5cq2hf0FU6Z+3B7MMXz14Kxyc3y18wUqxtgbvpFEfWF0bNUUq16JtWRljtxvZ83w==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/theme": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/theme/-/theme-3.12.0.tgz", + "integrity": "sha512-cdBi+wR1VOZ6URCcO9plmAZQu4ZGFcd7HJdBe7VIFiGyrvl9I/Of74ONLycnDImSuONt8D3uNjPBLieeaShVeg==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/thumbnail": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/thumbnail/-/thumbnail-3.12.0.tgz", + "integrity": "sha512-Vc8j3bO6wumWZV4o6pAbktPWKDSC9tQAzOCJ3cof541u4i44C11ccYC4W9aNcsMMUSO3bNwAGWtP8OFthV5akQ==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/toolbar": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/toolbar/-/toolbar-3.12.0.tgz", + "integrity": "sha512-qACTU3qXHgtNK8J+T13EWio+0liilj86SJ87BdapqXynhl720OKPlSKOQqskUGqg3oTUJAhrse9XG6SFdHJx+g==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0", + "@react-pdf-viewer/full-screen": "3.12.0", + "@react-pdf-viewer/get-file": "3.12.0", + "@react-pdf-viewer/open": "3.12.0", + "@react-pdf-viewer/page-navigation": "3.12.0", + "@react-pdf-viewer/print": "3.12.0", + "@react-pdf-viewer/properties": "3.12.0", + "@react-pdf-viewer/rotate": "3.12.0", + "@react-pdf-viewer/scroll-mode": "3.12.0", + "@react-pdf-viewer/search": "3.12.0", + "@react-pdf-viewer/selection-mode": "3.12.0", + "@react-pdf-viewer/theme": "3.12.0", + "@react-pdf-viewer/zoom": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/zoom": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/zoom/-/zoom-3.12.0.tgz", + "integrity": "sha512-V0GUTyPM77+LzhoKX+T3XI10/HfGdqRTbgeP7ID60FCzcwu6kXWqJn5tzabjDKLTlFv8mJmn0aa/ppkIU97nfA==", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@remix-run/router": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.6.3.tgz", + "integrity": "sha512-EXJysQ7J3veRECd0kZFQwYYd5sJMcq2O/m60zu1W2l3oVQ9xtub8jTOtYRE0+M2iomyG/W3Ps7+vp2kna0C27Q==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@rjsf/antd": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@rjsf/antd/-/antd-5.16.1.tgz", + "integrity": "sha512-bgv1wY44AxygeCrG31Rv9KtXz/R/vsD8PbSm9lyR4VwnqWPDiOSQCo0PyLHaS+hecU02bkR8D8+sCVZqeldolg==", + "dependencies": { + "classnames": "^2.5.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "rc-picker": "^2.7.6" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@ant-design/icons": "^4.0.0 || ^5.0.0", + "@rjsf/core": "^5.16.x", + "@rjsf/utils": "^5.16.x", + "antd": "^4.24.0 || ^5.8.5", + "dayjs": "^1.8.0", + "react": "^16.14.0 || >=17" + } + }, + "node_modules/@rjsf/core": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@rjsf/core/-/core-5.16.1.tgz", + "integrity": "sha512-zIqm5aJ0CfpqsJXcJvIEoYZMfPa6hLqKSeOwwifuHSjznC6fbXPdmqnifBCPVy0GgMaDDWekZLfndk5W3ZO1YA==", + "dependencies": { + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "markdown-to-jsx": "^7.4.0", + "nanoid": "^3.3.7", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@rjsf/utils": "^5.16.x", + "react": "^16.14.0 || >=17" + } + }, + "node_modules/@rjsf/utils": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.16.1.tgz", + "integrity": "sha512-zJ8WopscMl46QBjlIalIoPERs7kgSfUwIZ5zx4OMBRp0O+m7Scx0F+4iHqLnRuHEfaCNA5D7IKxmx1whOG/x1Q==", + "dependencies": { + "json-schema-merge-allof": "^0.8.1", + "jsonpointer": "^5.0.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.14.0 || >=17" + } + }, + "node_modules/@rjsf/validator-ajv8": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-5.8.1.tgz", + "integrity": "sha512-ImMd8nZeQzgt26y90yqEmiD7XPtDCX4LYGfniCr/PeAOk79OKhcdv8OMsdGTh9pGPtHy1qOJvntALKOpHGAeYg==", + "dependencies": { + "ajv": "^8.12.0", + "ajv-formats": "^2.1.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@rjsf/utils": "^5.8.x" + } + }, + "node_modules/@rollup/plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", + "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "dependencies": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-node-resolve/node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dependencies": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.2.tgz", + "integrity": "sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==" + }, + "node_modules/@sinclair/typebox": { + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==" + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, + "node_modules/@surma/rollup-plugin-off-main-thread": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", + "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "dependencies": { + "ejs": "^3.1.6", + "json5": "^2.2.0", + "magic-string": "^0.25.0", + "string.prototype.matchall": "^4.0.6" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", + "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", + "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", + "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", + "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", + "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", + "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", + "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", + "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", + "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", + "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", + "@svgr/babel-plugin-transform-svg-component": "^5.5.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", + "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", + "dependencies": { + "@svgr/plugin-jsx": "^5.5.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", + "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", + "dependencies": { + "@babel/types": "^7.12.6" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", + "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", + "dependencies": { + "@babel/core": "^7.12.3", + "@svgr/babel-preset": "^5.5.0", + "@svgr/hast-util-to-babel-ast": "^5.5.0", + "svg-parser": "^2.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", + "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", + "dependencies": { + "cosmiconfig": "^7.0.0", + "deepmerge": "^4.2.2", + "svgo": "^1.2.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", + "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/plugin-transform-react-constant-elements": "^7.12.1", + "@babel/preset-env": "^7.12.1", + "@babel/preset-react": "^7.12.5", + "@svgr/core": "^5.5.0", + "@svgr/plugin-jsx": "^5.5.0", + "@svgr/plugin-svgo": "^5.5.0", + "loader-utils": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@testing-library/dom": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz", + "integrity": "sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w==", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "5.16.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", + "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", + "dependencies": { + "@adobe/css-tools": "^4.0.1", + "@babel/runtime": "^7.9.2", + "@types/testing-library__jest-dom": "^5.9.1", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=8", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/react": { + "version": "13.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", + "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^8.5.0", + "@types/react-dom": "^18.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@testing-library/react/node_modules/@testing-library/dom": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz", + "integrity": "sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA==", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "^5.0.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.4.4", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@testing-library/user-event": { + "version": "13.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", + "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" + }, + "node_modules/@types/babel__core": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", + "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "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.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", + "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", + "integrity": "sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig==", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", + "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.40.2.tgz", + "integrity": "sha512-PRVjQ4Eh9z9pmmtaq8nTjZjQwKFk7YIHIud3lRoKRBgUQjgjRmoGxxGEPXQkF+lH7QkHJRNr5F4aBgYCW0lqpQ==", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" + }, + "node_modules/@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.35", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", + "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.11", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", + "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.2.tgz", + "integrity": "sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg==", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" + }, + "node_modules/@types/mdast": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.12.tgz", + "integrity": "sha512-DT+iNIRNX884cx0/Q1ja7NyUPpZuv0KPyL5rGNxm1WC1OtHstl7n4Jb7nk+xacNShQMbczJjt8uFzznpp6kYBg==", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, + "node_modules/@types/node": { + "version": "20.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", + "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==" + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "node_modules/@types/q": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", + "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "node_modules/@types/react": { + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.12.tgz", + "integrity": "sha512-ndmBMLCgn38v3SntMeoJaIrO6tGHYKMEBohCUmw8HoLLQdRMOIGXfeYaBTLe2lsFaSB3MOK1VXscYFnmLtTSmw==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.5.tgz", + "integrity": "sha512-sRQsOS/sCLnpQhR4DSKGTtWFE3FZjpQa86KPVbhUqdYMRZ9FEFcfAytKhR/vUG2rH1oFbOOej6cuD7MFSobDRQ==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "node_modules/@types/scheduler": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" + }, + "node_modules/@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==" + }, + "node_modules/@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" + }, + "node_modules/@types/testing-library__jest-dom": { + "version": "5.14.6", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.6.tgz", + "integrity": "sha512-FkHXCb+ikSoUP4Y4rOslzTdX5sqYwMxfefKh1GmZ8ce1GOkEHntSp6b5cGadmNfp5e4BMEWOMx+WSKd5/MqlDA==", + "dependencies": { + "@types/jest": "*" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", + "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==" + }, + "node_modules/@types/unist": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.7.tgz", + "integrity": "sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==" + }, + "node_modules/@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.11.tgz", + "integrity": "sha512-XxuOfTkCUiOSyBWIvHlUraLw/JT/6Io1365RO6ZuI88STKMavJZPNMU0lFcUTeQXEhHiv64CbxYxBNoDVSmghg==", + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.59.11", + "@typescript-eslint/type-utils": "5.59.11", + "@typescript-eslint/utils": "5.59.11", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.59.11.tgz", + "integrity": "sha512-GkQGV0UF/V5Ra7gZMBmiD1WrYUFOJNvCZs+XQnUyJoxmqfWMXVNyB2NVCPRKefoQcpvTv9UpJyfCvsJFs8NzzQ==", + "dependencies": { + "@typescript-eslint/utils": "5.59.11" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.11.tgz", + "integrity": "sha512-s9ZF3M+Nym6CAZEkJJeO2TFHHDsKAM3ecNkLuH4i4s8/RCPnF5JRip2GyviYkeEAcwGMJxkqG9h2dAsnA1nZpA==", + "dependencies": { + "@typescript-eslint/scope-manager": "5.59.11", + "@typescript-eslint/types": "5.59.11", + "@typescript-eslint/typescript-estree": "5.59.11", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.11.tgz", + "integrity": "sha512-dHFOsxoLFtrIcSj5h0QoBT/89hxQONwmn3FOQ0GOQcLOOXm+MIrS8zEAhs4tWl5MraxCY3ZJpaXQQdFMc2Tu+Q==", + "dependencies": { + "@typescript-eslint/types": "5.59.11", + "@typescript-eslint/visitor-keys": "5.59.11" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.11.tgz", + "integrity": "sha512-LZqVY8hMiVRF2a7/swmkStMYSoXMFlzL6sXV6U/2gL5cwnLWQgLEG8tjWPpaE4rMIdZ6VKWwcffPlo1jPfk43g==", + "dependencies": { + "@typescript-eslint/typescript-estree": "5.59.11", + "@typescript-eslint/utils": "5.59.11", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.11.tgz", + "integrity": "sha512-epoN6R6tkvBYSc+cllrz+c2sOFWkbisJZWkOE+y3xHtvYaOE6Wk6B8e114McRJwFRjGvYdJwLXQH5c9osME/AA==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.11.tgz", + "integrity": "sha512-YupOpot5hJO0maupJXixi6l5ETdrITxeo5eBOeuV7RSKgYdU3G5cxO49/9WRnJq9EMrB7AuTSLH/bqOsXi7wPA==", + "dependencies": { + "@typescript-eslint/types": "5.59.11", + "@typescript-eslint/visitor-keys": "5.59.11", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.11.tgz", + "integrity": "sha512-didu2rHSOMUdJThLk4aZ1Or8IcO3HzCw/ZvEjTTIfjIrcdd5cvSIwwDy2AOlE7htSNp7QIZ10fLMyRCveesMLg==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.59.11", + "@typescript-eslint/types": "5.59.11", + "@typescript-eslint/typescript-estree": "5.59.11", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.11.tgz", + "integrity": "sha512-KGYniTGG3AMTuKF9QBD7EIrvufkB6O6uX3knP73xbKLMpH+QRPcgnCxjWXSHjMRuOxFLovljqQgQpR0c7GvjoA==", + "dependencies": { + "@typescript-eslint/types": "5.59.11", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "optional": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/antd": { + "version": "5.13.2", + "resolved": "https://registry.npmjs.org/antd/-/antd-5.13.2.tgz", + "integrity": "sha512-P+N8gc0NOPy2WqJj/57Ey3dZUmb7nEUwAM+CIJaR5SOEjZnhEtMGRJSt+3lnhJ3MNRR39aR6NYkRVp2mYfphiA==", + "dependencies": { + "@ant-design/colors": "^7.0.2", + "@ant-design/cssinjs": "^1.18.2", + "@ant-design/icons": "^5.2.6", + "@ant-design/react-slick": "~1.0.2", + "@ctrl/tinycolor": "^3.6.1", + "@rc-component/color-picker": "~1.5.1", + "@rc-component/mutate-observer": "^1.1.0", + "@rc-component/tour": "~1.12.2", + "@rc-component/trigger": "^1.18.2", + "classnames": "^2.5.1", + "copy-to-clipboard": "^3.3.3", + "dayjs": "^1.11.10", + "qrcode.react": "^3.1.0", + "rc-cascader": "~3.21.0", + "rc-checkbox": "~3.1.0", + "rc-collapse": "~3.7.2", + "rc-dialog": "~9.3.4", + "rc-drawer": "~7.0.0", + "rc-dropdown": "~4.1.0", + "rc-field-form": "~1.41.0", + "rc-image": "~7.5.1", + "rc-input": "~1.4.3", + "rc-input-number": "~8.6.1", + "rc-mentions": "~2.10.1", + "rc-menu": "~9.12.4", + "rc-motion": "^2.9.0", + "rc-notification": "~5.3.0", + "rc-pagination": "~4.0.4", + "rc-picker": "~3.14.6", + "rc-progress": "~3.5.1", + "rc-rate": "~2.12.0", + "rc-resize-observer": "^1.4.0", + "rc-segmented": "~2.2.2", + "rc-select": "~14.11.0", + "rc-slider": "~10.5.0", + "rc-steps": "~6.0.1", + "rc-switch": "~4.1.0", + "rc-table": "~7.37.0", + "rc-tabs": "~14.0.0", + "rc-textarea": "~1.6.3", + "rc-tooltip": "~6.1.3", + "rc-tree": "~5.8.2", + "rc-tree-select": "~5.17.0", + "rc-upload": "~4.5.2", + "rc-util": "^5.38.1", + "scroll-into-view-if-needed": "^3.1.0", + "throttle-debounce": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ant-design" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/antd/node_modules/rc-picker": { + "version": "3.14.6", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-3.14.6.tgz", + "integrity": "sha512-AdKKW0AqMwZsKvIpwUWDUnpuGKZVrbxVTZTNjcO+pViGkjC1EBcjMgxVe8tomOEaIHJL5Gd13vS8Rr3zzxWmag==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^1.5.0", + "classnames": "^2.2.1", + "rc-util": "^5.30.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "date-fns": ">= 2.x", + "dayjs": ">= 1.x", + "luxon": ">= 3.x", + "moment": ">= 2.x", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + }, + "peerDependenciesMeta": { + "date-fns": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + } + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-tree-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz", + "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.reduce": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", + "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" + }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "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/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz", + "integrity": "sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/axios": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dependencies": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/babel-jest/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/babel-loader": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz", + "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==", + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/babel-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/babel-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/babel-loader/node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-macros/node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dependencies": { + "is-core-module": "^2.11.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/babel-plugin-named-asset-import": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", + "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", + "peerDependencies": { + "@babel/core": "^7.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.3.tgz", + "integrity": "sha512-bM3gHc337Dta490gg+/AseNB9L4YLHxq1nGKZZSHbhXv4aTYU2MD2cjza1Ru4S6975YLTaL1K8uJf6ukJhhmtw==", + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.4.0", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.1.tgz", + "integrity": "sha512-ikFrZITKg1xH6pLND8zT14UPgjKHiGLqex7rGEZCH2EvhsneJaJPemmpQaIZV5AL03II+lXylw3UmddDK8RU5Q==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.0", + "core-js-compat": "^3.30.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.0.tgz", + "integrity": "sha512-hDJtKjMLVa7Z+LwnTCxoDLQj6wdc+B8dun7ayF2fYieI6OzfuvcLMB32ihJZ4UhCBwNYGl5bg/x/P9cMdnkc2g==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==" + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dependencies": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-react-app": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz", + "integrity": "sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==", + "dependencies": { + "@babel/core": "^7.16.0", + "@babel/plugin-proposal-class-properties": "^7.16.0", + "@babel/plugin-proposal-decorators": "^7.16.4", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", + "@babel/plugin-proposal-numeric-separator": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.0", + "@babel/plugin-proposal-private-methods": "^7.16.0", + "@babel/plugin-transform-flow-strip-types": "^7.16.0", + "@babel/plugin-transform-react-display-name": "^7.16.0", + "@babel/plugin-transform-runtime": "^7.16.4", + "@babel/preset-env": "^7.16.4", + "@babel/preset-react": "^7.16.0", + "@babel/preset-typescript": "^7.16.0", + "@babel/runtime": "^7.16.3", + "babel-plugin-macros": "^3.1.0", + "babel-plugin-transform-react-remove-prop-types": "^0.4.24" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "node_modules/bfj": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", + "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", + "dependencies": { + "bluebird": "^3.5.5", + "check-types": "^11.1.1", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/bonjour-service": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" + }, + "node_modules/browserslist": { + "version": "4.21.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.8.tgz", + "integrity": "sha512-j+7xYe+v+q2Id9qbBeCI8WX5NmZSRe8es1+0xntD/+gaWXznP8tFEkv5IgSaHf5dS1YwVMbX/4W6m937mj+wQw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001502", + "electron-to-chromium": "^1.4.428", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001503", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz", + "integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/check-types": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.2.tgz", + "integrity": "sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA==" + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "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" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, + "node_modules/clean-css": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", + "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dependencies": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/coa/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/coa/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/coa/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/coa/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/coa/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/coa/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/coa/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/compute-gcd": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/compute-gcd/-/compute-gcd-1.2.1.tgz", + "integrity": "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==", + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, + "node_modules/compute-lcm": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/compute-lcm/-/compute-lcm-1.1.2.tgz", + "integrity": "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==", + "dependencies": { + "compute-gcd": "^1.2.1", + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz", + "integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "optional": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, + "node_modules/core-js": { + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.31.0.tgz", + "integrity": "sha512-NIp2TQSGfR6ba5aalZD+ZQ1fSxGhDo/s1w0nx3RYzf2pnJxt7YynxFlFScP6eV7+GZsKO95NSjGxyJsU3DZgeQ==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.31.0.tgz", + "integrity": "sha512-hM7YCu1cU6Opx7MXNu0NuumM0ezNeAeRKadixyiQELWY3vT3De9S4J5ZBMraWV2vZnrE1Cirl0GtFtDtMUXzPw==", + "dependencies": { + "browserslist": "^4.21.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.31.0.tgz", + "integrity": "sha512-/AnE9Y4OsJZicCzIe97JP5XoPKQJfTuEG43aEVLFJGOJpyqELod+pE6LEl63DfG1Mp8wX97LDaDpy1GmLEUxlg==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cron-validator": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cron-validator/-/cron-validator-1.3.1.tgz", + "integrity": "sha512-C1HsxuPCY/5opR55G5/WNzyEGDWFVG+6GLrA+fW/sCTcP6A6NTjUP2AK7B8n2PyFs90kDG2qzwm8LMheADku6A==" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-blank-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", + "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-has-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-loader": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", + "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.21", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.3", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-loader/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-loader/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "dependencies": { + "cssnano": "^5.0.6", + "jest-worker": "^27.0.2", + "postcss": "^8.3.5", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "bin": { + "css-prefers-color-scheme": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" + }, + "node_modules/css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dependencies": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-tree/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==" + }, + "node_modules/cssdb": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.6.0.tgz", + "integrity": "sha512-Nna7rph8V0jC6+JBY4Vk4ndErUmfJfV6NJCaZdurL0omggabiy+QB2HCQtu5c/ACLZ0I7REv7A4QyPIoYzZx0w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ] + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dependencies": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/csso/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==" + }, + "node_modules/deep-equal": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", + "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.0", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "optional": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/dnd-core": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz", + "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==", + "dependencies": { + "@react-dnd/asap": "^5.0.1", + "@react-dnd/invariant": "^4.0.1", + "redux": "^4.2.0" + } + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" + }, + "node_modules/dns-packet": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", + "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==" + }, + "node_modules/dom-align": { + "version": "1.12.4", + "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.4.tgz", + "integrity": "sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==" + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/ejs": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.431", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.431.tgz", + "integrity": "sha512-m232JTVmCawA2vG+1azVxhKZ9Sv1Q//xxNv5PkP5rWxGgQE8c3CiZFrh8Xnp+d1NmNxlu3QQrGIfdeW5TtXX5w==" + }, + "node_modules/emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io-client": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz", + "integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-abstract": { + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.0", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-module-lexer": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==" + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz", + "integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.42.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", + "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", + "import-fresh": "^3.0.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.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "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-config-google": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz", + "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "eslint": ">=5.16.0" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-config-react-app": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", + "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", + "dependencies": { + "@babel/core": "^7.16.0", + "@babel/eslint-parser": "^7.16.3", + "@rushstack/eslint-patch": "^1.1.0", + "@typescript-eslint/eslint-plugin": "^5.5.0", + "@typescript-eslint/parser": "^5.5.0", + "babel-preset-react-app": "^10.0.1", + "confusing-browser-globals": "^1.0.11", + "eslint-plugin-flowtype": "^8.0.3", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jest": "^25.3.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.27.1", + "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-testing-library": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dependencies": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-flowtype": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", + "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", + "dependencies": { + "lodash": "^4.17.21", + "string-natural-compare": "^3.0.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@babel/plugin-syntax-flow": "^7.14.5", + "@babel/plugin-transform-react-jsx": "^7.14.9", + "eslint": "^8.1.0" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dependencies": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "25.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", + "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", + "dependencies": { + "@typescript-eslint/experimental-utils": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^4.0.0 || ^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", + "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", + "dependencies": { + "@babel/runtime": "^7.20.7", + "aria-query": "^5.1.3", + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.6.2", + "axobject-query": "^3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.3", + "language-tags": "=1.0.5", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.8" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-testing-library": { + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.0.tgz", + "integrity": "sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q==", + "dependencies": { + "@typescript-eslint/utils": "^5.58.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0", + "npm": ">=6" + }, + "peerDependencies": { + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "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.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dependencies": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/espree": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "dependencies": { + "acorn": "^8.8.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/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "dependencies": { + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=10", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dependencies": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/fs-monkey": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz", + "integrity": "sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==" + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "optional": true + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-entities": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.6.tgz", + "integrity": "sha512-9o0+dcpIw2/HxkNuYKxSJUF/MMRZQECK4GnF+oQOmJ83yCVHTWgCH5aOXxK5bozNRmM8wtgryjHD3uloPBDEGw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", + "integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "webpack": "^5.20.0" + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" + }, + "node_modules/identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", + "dependencies": { + "harmony-reflect": "^1.4.6" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jake": { + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "dependencies": { + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "dependencies": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-circus/node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dependencies": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-cli/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-cli/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "dependencies": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-config/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-config/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-config/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-each/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-environment-jsdom/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-environment-node/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-haste-map/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-haste-map/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-haste-map/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-jasmine2/node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "dependencies": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.5.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-mock/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-mock/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-resolve/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-resolve/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve/node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dependencies": { + "is-core-module": "^2.11.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/jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-runner/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-runtime/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-snapshot/node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-validate/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-watch-typeahead": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-1.1.0.tgz", + "integrity": "sha512-Va5nLSJTN7YFtC2jd+7wsoe1pNe5K4ShLux/E5iHEwlB9AxaxmggY7to9KUqKojhaJw3aXqt5WAb4jGPOolpEw==", + "dependencies": { + "ansi-escapes": "^4.3.1", + "chalk": "^4.0.0", + "jest-regex-util": "^28.0.0", + "jest-watcher": "^28.0.0", + "slash": "^4.0.0", + "string-length": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "jest": "^27.0.0 || ^28.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@jest/console": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@jest/console/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@jest/test-result": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "dependencies": { + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "dependencies": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + }, + "node_modules/jest-watch-typeahead/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-message-util/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-watcher": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "dependencies": { + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-watcher/node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-watcher/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/string-length": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", + "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", + "dependencies": { + "char-regex": "^2.0.0", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/string-length/node_modules/char-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz", + "integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/jest-watch-typeahead/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "dependencies": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-watcher/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-watcher/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-watcher/node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", + "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/json-schema-compare": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/json-schema-compare/-/json-schema-compare-0.2.2.tgz", + "integrity": "sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ==", + "dependencies": { + "lodash": "^4.17.4" + } + }, + "node_modules/json-schema-merge-allof": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz", + "integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==", + "dependencies": { + "compute-lcm": "^1.1.2", + "json-schema-compare": "^0.2.2", + "lodash": "^4.17.20" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + }, + "node_modules/json2mq": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", + "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", + "dependencies": { + "string-convert": "^0.2.0" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dependencies": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" + }, + "node_modules/language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "dependencies": { + "language-subtag-registry": "~0.3.2" + } + }, + "node_modules/launch-editor": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", + "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.7.3" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/markdown-table": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", + "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/markdown-to-jsx": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.4.0.tgz", + "integrity": "sha512-zilc+MIkVVXPyTb4iIUTIz9yyqfcWjszGXnwF9K/aiBWcHXFcmdEMTkG01/oQhwSCH7SY1BnG6+ev5BzWmbPrg==", + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz", + "integrity": "sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==", + "dependencies": { + "@types/mdast": "^3.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", + "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz", + "integrity": "sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg==", + "dependencies": { + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-gfm-autolink-literal": "^1.0.0", + "mdast-util-gfm-footnote": "^1.0.0", + "mdast-util-gfm-strikethrough": "^1.0.0", + "mdast-util-gfm-table": "^1.0.0", + "mdast-util-gfm-task-list-item": "^1.0.0", + "mdast-util-to-markdown": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz", + "integrity": "sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==", + "dependencies": { + "@types/mdast": "^3.0.0", + "ccount": "^2.0.0", + "mdast-util-find-and-replace": "^2.0.0", + "micromark-util-character": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz", + "integrity": "sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0", + "micromark-util-normalize-identifier": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz", + "integrity": "sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz", + "integrity": "sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==", + "dependencies": { + "@types/mdast": "^3.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-to-markdown": "^1.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz", + "integrity": "sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-3.0.1.tgz", + "integrity": "sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg==", + "dependencies": { + "@types/mdast": "^3.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz", + "integrity": "sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^3.0.0", + "mdast-util-to-string": "^3.0.0", + "micromark-util-decode-string": "^1.0.0", + "unist-util-visit": "^4.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", + "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", + "dependencies": { + "@types/mdast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", + "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", + "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.3.tgz", + "integrity": "sha512-vb9OoHqrhCmbRidQv/2+Bc6pkP0FrtlhurxZofvOEy5o8RtuuvTq+RQ1Vw5ZDNrVraQZu3HixESqbG+0iKk/MQ==", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^1.0.0", + "micromark-extension-gfm-footnote": "^1.0.0", + "micromark-extension-gfm-strikethrough": "^1.0.0", + "micromark-extension-gfm-table": "^1.0.0", + "micromark-extension-gfm-tagfilter": "^1.0.0", + "micromark-extension-gfm-task-list-item": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.5.tgz", + "integrity": "sha512-z3wJSLrDf8kRDOh2qBtoTRD53vJ+CWIyo7uyZuxf/JAbNJjiHsOpG1y5wxk8drtv3ETAHutCu6N3thkOOgueWg==", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.1.2.tgz", + "integrity": "sha512-Yxn7z7SxgyGWRNa4wzf8AhYYWNrwl5q1Z8ii+CSTTIqVkmGZF1CElX2JI8g5yGoM3GAman9/PVCUFUSJ0kB/8Q==", + "dependencies": { + "micromark-core-commonmark": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.7.tgz", + "integrity": "sha512-sX0FawVE1o3abGk3vRjOH50L5TTLr3b5XMqnP9YDRb34M0v5OoZhG+OHFz1OffZ9dlwgpTBKaT4XW/AsUVnSDw==", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.7.tgz", + "integrity": "sha512-3ZORTHtcSnMQEKtAOsBQ9/oHp9096pI/UvdPtN7ehKvrmZZ2+bbWhi0ln+I9drmwXMt5boocn6OlwQzNXeVeqw==", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.2.tgz", + "integrity": "sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g==", + "dependencies": { + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.5.tgz", + "integrity": "sha512-RMFXl2uQ0pNQy6Lun2YBYT9g9INXtWJULgbt01D/x8/6yJ2qpKyzdZD3pi6UIkzF++Da49xAelVKUeUMqd5eIQ==", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", + "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", + "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", + "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", + "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", + "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", + "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", + "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz", + "integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz", + "integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", + "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", + "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", + "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", + "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", + "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", + "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", + "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nan": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", + "optional": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "optional": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "optional": true + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "optional": true + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "optional": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + }, + "node_modules/node-releases": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "optional": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.5.tgz", + "integrity": "sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ==" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.6.tgz", + "integrity": "sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==", + "dependencies": { + "array.prototype.reduce": "^1.0.5", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.21.2", + "safe-array-concat": "^1.0.0" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "dependencies": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path2d-polyfill": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", + "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/pdfjs-dist": { + "version": "3.4.120", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.4.120.tgz", + "integrity": "sha512-B1hw9ilLG4m/jNeFA0C2A0PZydjxslP8ylU+I4XM7Bzh/xWETo9EiBV848lh0O0hLut7T6lK1V7cpAXv5BhxWw==", + "dependencies": { + "path2d-polyfill": "^2.0.1", + "web-streams-polyfill": "^3.2.1" + }, + "optionalDependencies": { + "canvas": "^2.11.0" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.4.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", + "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-browser-comments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", + "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "browserslist": ">=4", + "postcss": ">=8" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-custom-properties": { + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-flexbugs-fixes": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", + "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", + "peerDependencies": { + "postcss": "^8.1.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "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-import/node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dependencies": { + "is-core-module": "^2.11.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/postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "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-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", + "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^2.1.1" + }, + "engines": { + "node": ">= 14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "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/yaml": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", + "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-loader/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-loader/node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-loader/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "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-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-normalize": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-10.0.1.tgz", + "integrity": "sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA==", + "dependencies": { + "@csstools/normalize.css": "*", + "postcss-browser-comments": "^4", + "sanitize.css": "*" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "browserslist": ">= 4", + "postcss": ">= 8" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", + "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-preset-env": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.3.tgz", + "integrity": "sha512-T1LgRm5uEVFSEF83vHZJV2z19lHg4yJuZ6gXZZkqVsqv63nlr6zabMH3l4Pc01FQCyfWVrh2GaUeCVy9Po+Aag==", + "dependencies": { + "@csstools/postcss-cascade-layers": "^1.1.1", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.1.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.10", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.2.0", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/postcss-svgo/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/postcss-svgo/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/postcss-svgo/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-svgo/node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/prettier-quick": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/prettier-quick/-/prettier-quick-0.0.5.tgz", + "integrity": "sha512-5zOMSPAK7JQMNWjtxAy35XPgRN8TQY+khgpNhznQ30Zsv6V0hOIjre8X5cTrtdqa3NKZWWF1+TNS5+1LX/3a0w==", + "dev": true + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qrcode.react": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-3.1.0.tgz", + "integrity": "sha512-oyF+Urr3oAMUG/OiOuONL3HXM+53wvuH3mtIWQrYmsXoAq0DkvZp2RYUWFSMFtbdOpuS++9v+WAkzNVkMlNW6Q==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "dependencies": { + "performance-now": "^2.1.0" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rc-align": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-4.0.15.tgz", + "integrity": "sha512-wqJtVH60pka/nOX7/IspElA8gjPNQKIx/ZqJ6heATCkXpe1Zg4cPVrMD2vC96wjsFFL8WsmhPbx9tdMo1qqlIA==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "dom-align": "^1.7.0", + "rc-util": "^5.26.0", + "resize-observer-polyfill": "^1.5.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-cascader": { + "version": "3.21.2", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.21.2.tgz", + "integrity": "sha512-J7GozpgsLaOtzfIHFJFuh4oFY0ePb1w10twqK6is3pAkqHkca/PsokbDr822KIRZ8/CK8CqevxohuPDVZ1RO/A==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "array-tree-filter": "^2.1.0", + "classnames": "^2.3.1", + "rc-select": "~14.11.0", + "rc-tree": "~5.8.1", + "rc-util": "^5.37.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-checkbox": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.1.0.tgz", + "integrity": "sha512-PAwpJFnBa3Ei+5pyqMMXdcKYKNBMS+TvSDiLdDnARnMJHC8ESxwPfm4Ao1gJiKtWLdmGfigascnCpwrHFgoOBQ==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.25.2" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-collapse": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.7.2.tgz", + "integrity": "sha512-ZRw6ipDyOnfLFySxAiCMdbHtb5ePAsB9mT17PA6y1mRD/W6KHRaZeb5qK/X9xDV1CqgyxMpzw0VdS74PCcUk4A==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.3.4", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-dialog": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.3.4.tgz", + "integrity": "sha512-975X3018GhR+EjZFbxA2Z57SX5rnu0G0/OxFgMMvZK4/hQWEm3MHaNvP4wXpxYDoJsp+xUvVW+GB9CMMCm81jA==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/portal": "^1.0.0-8", + "classnames": "^2.2.6", + "rc-motion": "^2.3.0", + "rc-util": "^5.21.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-drawer": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.0.0.tgz", + "integrity": "sha512-ePcS4KtQnn57bCbVXazHN2iC8nTPCXlWEIA/Pft87Pd9U7ZeDkdRzG47jWG2/TAFXFlFltRAMcslqmUM8NPCGA==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/portal": "^1.1.1", + "classnames": "^2.2.6", + "rc-motion": "^2.6.1", + "rc-util": "^5.36.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-dropdown": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.1.0.tgz", + "integrity": "sha512-VZjMunpBdlVzYpEdJSaV7WM7O0jf8uyDjirxXLZRNZ+tAC+NzD3PXPEtliFwGzVwBBdCmGuSqiS9DWcOLxQ9tw==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@rc-component/trigger": "^1.7.0", + "classnames": "^2.2.6", + "rc-util": "^5.17.0" + }, + "peerDependencies": { + "react": ">=16.11.0", + "react-dom": ">=16.11.0" + } + }, + "node_modules/rc-field-form": { + "version": "1.41.0", + "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.41.0.tgz", + "integrity": "sha512-k9AS0wmxfJfusWDP/YXWTpteDNaQ4isJx9UKxx4/e8Dub4spFeZ54/EuN2sYrMRID/+hUznPgVZeg+Gf7XSYCw==", + "dependencies": { + "@babel/runtime": "^7.18.0", + "async-validator": "^4.1.0", + "rc-util": "^5.32.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-image": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.5.1.tgz", + "integrity": "sha512-Z9loECh92SQp0nSipc0MBuf5+yVC05H/pzC+Nf8xw1BKDFUJzUeehYBjaWlxly8VGBZJcTHYri61Fz9ng1G3Ag==", + "dependencies": { + "@babel/runtime": "^7.11.2", + "@rc-component/portal": "^1.0.2", + "classnames": "^2.2.6", + "rc-dialog": "~9.3.4", + "rc-motion": "^2.6.2", + "rc-util": "^5.34.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-input": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.4.3.tgz", + "integrity": "sha512-aHyQUAIRmTlOnvk5EcNqEpJ+XMtfMpYRAJayIlJfsvvH9cAKUWboh4egm23vgMA7E+c/qm4BZcnrDcA960GC1w==", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.18.1" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/rc-input-number": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-8.6.1.tgz", + "integrity": "sha512-gaAMUKtUKLktJ3Yx93tjgYY1M0HunnoqzPEqkb9//Ydup4DcG0TFL9yHBA3pgVdNIt5f0UWyHCgFBj//JxeD6A==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/mini-decimal": "^1.0.1", + "classnames": "^2.2.5", + "rc-input": "~1.4.0", + "rc-util": "^5.28.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-mentions": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.10.1.tgz", + "integrity": "sha512-72qsEcr/7su+a07ndJ1j8rI9n0Ka/ngWOLYnWMMv0p2mi/5zPwPrEDTt6Uqpe8FWjWhueDJx/vzunL6IdKDYMg==", + "dependencies": { + "@babel/runtime": "^7.22.5", + "@rc-component/trigger": "^1.5.0", + "classnames": "^2.2.6", + "rc-input": "~1.4.0", + "rc-menu": "~9.12.0", + "rc-textarea": "~1.6.1", + "rc-util": "^5.34.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-menu": { + "version": "9.12.4", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.12.4.tgz", + "integrity": "sha512-t2NcvPLV1mFJzw4F21ojOoRVofK2rWhpKPx69q2raUsiHPDP6DDevsBILEYdsIegqBeSXoWs2bf6CueBKg3BFg==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^1.17.0", + "classnames": "2.x", + "rc-motion": "^2.4.3", + "rc-overflow": "^1.3.1", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-motion": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.9.0.tgz", + "integrity": "sha512-XIU2+xLkdIr1/h6ohPZXyPBMvOmuyFZQ/T0xnawz+Rh+gh4FINcnZmMT5UTIj6hgI0VLDjTaPeRd+smJeSPqiQ==", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.21.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-notification": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.3.0.tgz", + "integrity": "sha512-WCf0uCOkZ3HGfF0p1H4Sgt7aWfipxORWTPp7o6prA3vxwtWhtug3GfpYls1pnBp4WA+j8vGIi5c2/hQRpGzPcQ==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.9.0", + "rc-util": "^5.20.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-overflow": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.3.2.tgz", + "integrity": "sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.37.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-pagination": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-4.0.4.tgz", + "integrity": "sha512-GGrLT4NgG6wgJpT/hHIpL9nELv27A1XbSZzECIuQBQTVSf4xGKxWr6I/jhpRPauYEWEbWVw22ObG6tJQqwJqWQ==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.38.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-picker": { + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.7.6.tgz", + "integrity": "sha512-H9if/BUJUZBOhPfWcPeT15JUI3/ntrG9muzERrXDkSoWmDj4yzmBvumozpxYrHwjcKnjyDGAke68d+whWwvhHA==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "date-fns": "2.x", + "dayjs": "1.x", + "moment": "^2.24.0", + "rc-trigger": "^5.0.4", + "rc-util": "^5.37.0", + "shallowequal": "^1.1.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-progress": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-3.5.1.tgz", + "integrity": "sha512-V6Amx6SbLRwPin/oD+k1vbPrO8+9Qf8zW1T8A7o83HdNafEVvAxPV5YsgtKFP+Ud5HghLj33zKOcEHrcrUGkfw==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-util": "^5.16.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-rate": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.12.0.tgz", + "integrity": "sha512-g092v5iZCdVzbjdn28FzvWebK2IutoVoiTeqoLTj9WM7SjA/gOJIw5/JFZMRyJYYVe1jLAU2UhAfstIpCNRozg==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.0.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-resize-observer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.0.tgz", + "integrity": "sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q==", + "dependencies": { + "@babel/runtime": "^7.20.7", + "classnames": "^2.2.1", + "rc-util": "^5.38.0", + "resize-observer-polyfill": "^1.5.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-segmented": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.2.2.tgz", + "integrity": "sha512-Mq52M96QdHMsNdE/042ibT5vkcGcD5jxKp7HgPC2SRofpia99P5fkfHy1pEaajLMF/kj0+2Lkq1UZRvqzo9mSA==", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-motion": "^2.4.4", + "rc-util": "^5.17.0" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/rc-select": { + "version": "14.11.0", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.11.0.tgz", + "integrity": "sha512-8J8G/7duaGjFiTXCBLWfh5P+KDWyA3KTlZDfV3xj/asMPqB2cmxfM+lH50wRiPIRsCQ6EbkCFBccPuaje3DHIg==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^1.5.0", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-overflow": "^1.3.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-slider": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-10.5.0.tgz", + "integrity": "sha512-xiYght50cvoODZYI43v3Ylsqiw14+D7ELsgzR40boDZaya1HFa1Etnv9MDkQE8X/UrXAffwv2AcNAhslgYuDTw==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.27.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-steps": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-6.0.1.tgz", + "integrity": "sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==", + "dependencies": { + "@babel/runtime": "^7.16.7", + "classnames": "^2.2.3", + "rc-util": "^5.16.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-switch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz", + "integrity": "sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "classnames": "^2.2.1", + "rc-util": "^5.30.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-table": { + "version": "7.37.0", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.37.0.tgz", + "integrity": "sha512-hEB17ktLRVfVmdo+U8MjGr+PuIgdQ8Cxj/N5lwMvP/Az7TOrQxwTMLVEDoj207tyPYLTWifHIF9EJREWwyk67g==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/context": "^1.4.0", + "classnames": "^2.2.5", + "rc-resize-observer": "^1.1.0", + "rc-util": "^5.37.0", + "rc-virtual-list": "^3.11.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tabs": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-14.0.0.tgz", + "integrity": "sha512-lp1YWkaPnjlyhOZCPrAWxK6/P6nMGX/BAZcAC3nuVwKz0Byfp+vNnQKK8BRCP2g/fzu+SeB5dm9aUigRu3tRkQ==", + "dependencies": { + "@babel/runtime": "^7.11.2", + "classnames": "2.x", + "rc-dropdown": "~4.1.0", + "rc-menu": "~9.12.0", + "rc-motion": "^2.6.2", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.34.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-textarea": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.6.3.tgz", + "integrity": "sha512-8k7+8Y2GJ/cQLiClFMg8kUXOOdvcFQrnGeSchOvI2ZMIVvX5a3zQpLxoODL0HTrvU63fPkRmMuqaEcOF9dQemA==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-input": "~1.4.0", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tooltip": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.1.3.tgz", + "integrity": "sha512-HMSbSs5oieZ7XddtINUddBLSVgsnlaSb3bZrzzGWjXa7/B7nNedmsuz72s7EWFEro9mNa7RyF3gOXKYqvJiTcQ==", + "dependencies": { + "@babel/runtime": "^7.11.2", + "@rc-component/trigger": "^1.18.0", + "classnames": "^2.3.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tree": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.8.2.tgz", + "integrity": "sha512-xH/fcgLHWTLmrSuNphU8XAqV7CdaOQgm4KywlLGNoTMhDAcNR3GVNP6cZzb0GrKmIZ9yae+QLot/cAgUdPRMzg==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.1" + }, + "engines": { + "node": ">=10.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-tree-select": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.17.0.tgz", + "integrity": "sha512-7sRGafswBhf7n6IuHyCEFCildwQIgyKiV8zfYyUoWfZEFdhuk7lCH+DN0aHt+oJrdiY9+6Io/LDXloGe01O8XQ==", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-select": "~14.11.0-0", + "rc-tree": "~5.8.1", + "rc-util": "^5.16.1" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-trigger": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.3.4.tgz", + "integrity": "sha512-mQv+vas0TwKcjAO2izNPkqR4j86OemLRmvL2nOzdP9OWNWA1ivoTt5hzFqYNW9zACwmTezRiN8bttrC7cZzYSw==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "classnames": "^2.2.6", + "rc-align": "^4.0.0", + "rc-motion": "^2.0.0", + "rc-util": "^5.19.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-upload": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.5.2.tgz", + "integrity": "sha512-QO3ne77DwnAPKFn0bA5qJM81QBjQi0e0NHdkvpFyY73Bea2NfITiotqJqVjHgeYPOJu5lLVR32TNGP084aSoXA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "classnames": "^2.2.5", + "rc-util": "^5.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-util": { + "version": "5.38.1", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.38.1.tgz", + "integrity": "sha512-e4ZMs7q9XqwTuhIK7zBIVFltUtMSjphuPPQXHoHlzRzNdOwUxDejo0Zls5HYaJfRKNURcsS/ceKVULlhjBrxng==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "react-is": "^18.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-virtual-list": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.11.3.tgz", + "integrity": "sha512-tu5UtrMk/AXonHwHxUogdXAWynaXsrx1i6dsgg+lOo/KJSF8oBAcprh1z5J3xgnPJD5hXxTL58F8s8onokdt0Q==", + "dependencies": { + "@babel/runtime": "^7.20.0", + "classnames": "^2.2.6", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.36.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-app-polyfill": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz", + "integrity": "sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==", + "dependencies": { + "core-js": "^3.19.2", + "object-assign": "^4.1.1", + "promise": "^8.1.0", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.9", + "whatwg-fetch": "^3.6.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "dependencies": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-dev-utils/node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/react-dnd": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", + "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==", + "dependencies": { + "@react-dnd/invariant": "^4.0.1", + "@react-dnd/shallowequal": "^4.0.1", + "dnd-core": "^16.0.1", + "fast-deep-equal": "^3.1.3", + "hoist-non-react-statics": "^3.3.2" + }, + "peerDependencies": { + "@types/hoist-non-react-statics": ">= 3.3.1", + "@types/node": ">= 12", + "@types/react": ">= 16", + "react": ">= 16.14" + }, + "peerDependenciesMeta": { + "@types/hoist-non-react-statics": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-dnd-html5-backend": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz", + "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==", + "dependencies": { + "dnd-core": "^16.0.1" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/react-refresh": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", + "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.13.0.tgz", + "integrity": "sha512-Si6KnfEnJw7gUQkNa70dlpI1bul46FuSxX5t5WwlUBxE25DAz2BjVkwaK8Y2s242bQrZPXCpmwLPtIO5pv4tXg==", + "dependencies": { + "@remix-run/router": "1.6.3" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.13.0.tgz", + "integrity": "sha512-6Nqoqd7fgwxxVGdbiMHTpDHCYPq62d7Wk1Of7B82vH7ZPwwsRaIa22zRZKPPg413R5REVNiyuQPKDG1bubcOFA==", + "dependencies": { + "@remix-run/router": "1.6.3", + "react-router": "6.13.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-scripts": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", + "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", + "dependencies": { + "@babel/core": "^7.16.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", + "@svgr/webpack": "^5.5.0", + "babel-jest": "^27.4.2", + "babel-loader": "^8.2.3", + "babel-plugin-named-asset-import": "^0.3.8", + "babel-preset-react-app": "^10.0.1", + "bfj": "^7.0.2", + "browserslist": "^4.18.1", + "camelcase": "^6.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "css-loader": "^6.5.1", + "css-minimizer-webpack-plugin": "^3.2.0", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "eslint": "^8.3.0", + "eslint-config-react-app": "^7.0.1", + "eslint-webpack-plugin": "^3.1.1", + "file-loader": "^6.2.0", + "fs-extra": "^10.0.0", + "html-webpack-plugin": "^5.5.0", + "identity-obj-proxy": "^3.0.0", + "jest": "^27.4.3", + "jest-resolve": "^27.4.2", + "jest-watch-typeahead": "^1.0.0", + "mini-css-extract-plugin": "^2.4.5", + "postcss": "^8.4.4", + "postcss-flexbugs-fixes": "^5.0.2", + "postcss-loader": "^6.2.1", + "postcss-normalize": "^10.0.1", + "postcss-preset-env": "^7.0.1", + "prompts": "^2.4.2", + "react-app-polyfill": "^3.0.0", + "react-dev-utils": "^12.0.1", + "react-refresh": "^0.11.0", + "resolve": "^1.20.0", + "resolve-url-loader": "^4.0.0", + "sass-loader": "^12.3.0", + "semver": "^7.3.5", + "source-map-loader": "^3.0.0", + "style-loader": "^3.3.1", + "tailwindcss": "^3.0.2", + "terser-webpack-plugin": "^5.2.5", + "webpack": "^5.64.4", + "webpack-dev-server": "^4.6.0", + "webpack-manifest-plugin": "^4.0.2", + "workbox-webpack-plugin": "^6.4.1" + }, + "bin": { + "react-scripts": "bin/react-scripts.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + }, + "peerDependencies": { + "react": ">= 16", + "typescript": "^3.2.1 || ^4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/react-scripts/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-scripts/node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dependencies": { + "is-core-module": "^2.11.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/react-scripts/node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-scripts/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/react-social-login-buttons": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/react-social-login-buttons/-/react-social-login-buttons-3.9.1.tgz", + "integrity": "sha512-KtucVWvdnIZ0icG99WJ3usQUJYmlKsOIBYGyngcuNSVyyYdZtif4KHY80qnCg+teDlgYr54ToQtg3x26ZqaS2w==", + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.x || ^18.x" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remark-gfm": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", + "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-gfm": "^2.0.0", + "micromark-extension-gfm": "^2.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "node_modules/resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-url-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", + "integrity": "sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==", + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^7.0.35", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=8.9" + }, + "peerDependencies": { + "rework": "1.0.1", + "rework-visit": "1.0.0" + }, + "peerDependenciesMeta": { + "rework": { + "optional": true + }, + "rework-visit": { + "optional": true + } + } + }, + "node_modules/resolve-url-loader/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "node_modules/resolve-url-loader/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sanitize.css": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", + "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" + }, + "node_modules/sass-loader": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/scroll-into-view-if-needed": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", + "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==", + "dependencies": { + "compute-scroll-into-view": "^3.0.2" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "node_modules/selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "optional": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/socket.io-client": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", + "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", + "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", + "dependencies": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead" + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-convert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", + "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==" + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", + "integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==", + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/stylis": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", + "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==" + }, + "node_modules/sucrase": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", + "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "7.1.6", + "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": ">=8" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "node_modules/svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "deprecated": "This SVGO version is no longer supported. Upgrade to v2.x.x.", + "dependencies": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/svgo/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/svgo/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/svgo/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/svgo/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/svgo/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/svgo/node_modules/css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "node_modules/svgo/node_modules/css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dependencies": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/svgo/node_modules/domutils/node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "node_modules/svgo/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/svgo/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/svgo/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/svgo/node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/svgo/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, + "node_modules/tailwindcss": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", + "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", + "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.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.18.2", + "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", + "postcss-value-parser": "^4.2.0", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dependencies": { + "is-core-module": "^2.11.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/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "optional": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "dependencies": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.18.0.tgz", + "integrity": "sha512-pdL757Ig5a0I+owA42l6tIuEycRuM7FPY4n62h44mRLRfnOxJkkOHd6i89dOpwZlpF6JXBwaAHF6yWzFrt+QyA==", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/throat": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", + "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==" + }, + "node_modules/throttle-debounce": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.0.tgz", + "integrity": "sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg==", + "engines": { + "node": ">=12.22" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==" + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==" + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "dependencies": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "bin": { + "uvu": "bin.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/uvu/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/validate.io-array": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz", + "integrity": "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==" + }, + "node_modules/validate.io-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz", + "integrity": "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==" + }, + "node_modules/validate.io-integer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz", + "integrity": "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==", + "dependencies": { + "validate.io-number": "^1.0.3" + } + }, + "node_modules/validate.io-integer-array": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz", + "integrity": "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==", + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-integer": "^1.0.4" + } + }, + "node_modules/validate.io-number": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz", + "integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "engines": { + "node": ">=10.4" + } + }, + "node_modules/webpack": { + "version": "5.87.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.87.0.tgz", + "integrity": "sha512-GOu1tNbQ7p1bDEoFRs2YPcfyGs8xq52yyPBZ3m2VGnXGtV9MxjrkABHm4V9Ia280OefsSLzvbVoXcfLxjKY/Iw==", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-manifest-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", + "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", + "dependencies": { + "tapable": "^2.0.0", + "webpack-sources": "^2.2.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "peerDependencies": { + "webpack": "^4.44.2 || ^5.47.0" + } + }, + "node_modules/webpack-manifest-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-manifest-plugin/node_modules/webpack-sources": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", + "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", + "dependencies": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" + }, + "node_modules/workbox-background-sync": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.6.0.tgz", + "integrity": "sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-broadcast-update": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.6.0.tgz", + "integrity": "sha512-nm+v6QmrIFaB/yokJmQ/93qIJ7n72NICxIwQwe5xsZiV2aI93MGGyEyzOzDPVz5THEr5rC3FJSsO3346cId64Q==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-build": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.6.0.tgz", + "integrity": "sha512-Tjf+gBwOTuGyZwMz2Nk/B13Fuyeo0Q84W++bebbVsfr9iLkDSo6j6PST8tET9HYA58mlRXwlMGpyWO8ETJiXdQ==", + "dependencies": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.11.1", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^5.2.0", + "@rollup/plugin-node-resolve": "^11.2.1", + "@rollup/plugin-replace": "^2.4.1", + "@surma/rollup-plugin-off-main-thread": "^2.2.3", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "lodash": "^4.17.20", + "pretty-bytes": "^5.3.0", + "rollup": "^2.43.1", + "rollup-plugin-terser": "^7.0.0", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "6.6.0", + "workbox-broadcast-update": "6.6.0", + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-google-analytics": "6.6.0", + "workbox-navigation-preload": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-range-requests": "6.6.0", + "workbox-recipes": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0", + "workbox-streams": "6.6.0", + "workbox-sw": "6.6.0", + "workbox-window": "6.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/workbox-build/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/workbox-build/node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workbox-build/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/workbox-build/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "node_modules/workbox-build/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/workbox-cacheable-response": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.6.0.tgz", + "integrity": "sha512-JfhJUSQDwsF1Xv3EV1vWzSsCOZn4mQ38bWEBR3LdvOxSPgB65gAM6cS2CX8rkkKHRgiLrN7Wxoyu+TuH67kHrw==", + "deprecated": "workbox-background-sync@6.6.0", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-core": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.6.0.tgz", + "integrity": "sha512-GDtFRF7Yg3DD859PMbPAYPeJyg5gJYXuBQAC+wyrWuuXgpfoOrIQIvFRZnQ7+czTIQjIr1DhLEGFzZanAT/3bQ==" + }, + "node_modules/workbox-expiration": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.6.0.tgz", + "integrity": "sha512-baplYXcDHbe8vAo7GYvyAmlS4f6998Jff513L4XvlzAOxcl8F620O91guoJ5EOf5qeXG4cGdNZHkkVAPouFCpw==", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-google-analytics": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.6.0.tgz", + "integrity": "sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==", + "dependencies": { + "workbox-background-sync": "6.6.0", + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/workbox-navigation-preload": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.6.0.tgz", + "integrity": "sha512-utNEWG+uOfXdaZmvhshrh7KzhDu/1iMHyQOV6Aqup8Mm78D286ugu5k9MFD9SzBT5TcwgwSORVvInaXWbvKz9Q==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-precaching": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.6.0.tgz", + "integrity": "sha512-eYu/7MqtRZN1IDttl/UQcSZFkHP7dnvr/X3Vn6Iw6OsPMruQHiVjjomDFCNtd8k2RdjLs0xiz9nq+t3YVBcWPw==", + "dependencies": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/workbox-range-requests": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.6.0.tgz", + "integrity": "sha512-V3aICz5fLGq5DpSYEU8LxeXvsT//mRWzKrfBOIxzIdQnV/Wj7R+LyJVTczi4CQ4NwKhAaBVaSujI1cEjXW+hTw==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-recipes": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.6.0.tgz", + "integrity": "sha512-TFi3kTgYw73t5tg73yPVqQC8QQjxJSeqjXRO4ouE/CeypmP2O/xqmB/ZFBBQazLTPxILUQ0b8aeh0IuxVn9a6A==", + "dependencies": { + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "node_modules/workbox-routing": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.6.0.tgz", + "integrity": "sha512-x8gdN7VDBiLC03izAZRfU+WKUXJnbqt6PG9Uh0XuPRzJPpZGLKce/FkOX95dWHRpOHWLEq8RXzjW0O+POSkKvw==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-strategies": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.6.0.tgz", + "integrity": "sha512-eC07XGuINAKUWDnZeIPdRdVja4JQtTuc35TZ8SwMb1ztjp7Ddq2CJ4yqLvWzFWGlYI7CG/YGqaETntTxBGdKgQ==", + "dependencies": { + "workbox-core": "6.6.0" + } + }, + "node_modules/workbox-streams": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.6.0.tgz", + "integrity": "sha512-rfMJLVvwuED09CnH1RnIep7L9+mj4ufkTyDPVaXPKlhi9+0czCu+SJggWCIFbPpJaAZmp2iyVGLqS3RUmY3fxg==", + "dependencies": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0" + } + }, + "node_modules/workbox-sw": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.6.0.tgz", + "integrity": "sha512-R2IkwDokbtHUE4Kus8pKO5+VkPHD2oqTgl+XJwh4zbF1HyjAbgNmK/FneZHVU7p03XUt9ICfuGDYISWG9qV/CQ==" + }, + "node_modules/workbox-webpack-plugin": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.6.0.tgz", + "integrity": "sha512-xNZIZHalboZU66Wa7x1YkjIqEy1gTR+zPM+kjrYJzqN7iurYZBctBLISyScjhkJKYuRrZUP0iqViZTh8rS0+3A==", + "dependencies": { + "fast-json-stable-stringify": "^2.1.0", + "pretty-bytes": "^5.4.1", + "upath": "^1.2.0", + "webpack-sources": "^1.4.3", + "workbox-build": "6.6.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "webpack": "^4.4.0 || ^5.9.0" + } + }, + "node_modules/workbox-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workbox-webpack-plugin/node_modules/webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/workbox-window": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.6.0.tgz", + "integrity": "sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==", + "dependencies": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "6.6.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zustand": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.8.tgz", + "integrity": "sha512-4h28KCkHg5ii/wcFFJ5Fp+k1J3gJoasaIbppdgZFO4BPJnsNxL0mQXBSFgOgAdCdBj35aDTPvdAJReTMntFPGg==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "immer": ">=9.0", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + }, + "dependencies": { + "@adobe/css-tools": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz", + "integrity": "sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==" + }, + "@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==" + }, + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@ant-design/colors": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.0.2.tgz", + "integrity": "sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg==", + "requires": { + "@ctrl/tinycolor": "^3.6.1" + } + }, + "@ant-design/cssinjs": { + "version": "1.18.4", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.18.4.tgz", + "integrity": "sha512-IrUAOj5TYuMG556C9gdbFuOrigyhzhU5ZYpWb3gYTxAwymVqRbvLzFCZg6OsjLBR6GhzcxYF3AhxKmjB+rA2xA==", + "requires": { + "@babel/runtime": "^7.11.1", + "@emotion/hash": "^0.8.0", + "@emotion/unitless": "^0.7.5", + "classnames": "^2.3.1", + "csstype": "^3.1.3", + "rc-util": "^5.35.0", + "stylis": "^4.0.13" + } + }, + "@ant-design/icons": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.2.6.tgz", + "integrity": "sha512-4wn0WShF43TrggskBJPRqCD0fcHbzTYjnaoskdiJrVHg86yxoZ8ZUqsXvyn4WUqehRiFKnaclOhqk9w4Ui2KVw==", + "requires": { + "@ant-design/colors": "^7.0.0", + "@ant-design/icons-svg": "^4.3.0", + "@babel/runtime": "^7.11.2", + "classnames": "^2.2.6", + "rc-util": "^5.31.1" + } + }, + "@ant-design/icons-svg": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.3.1.tgz", + "integrity": "sha512-4QBZg8ccyC6LPIRii7A0bZUk3+lEDCLnhB+FVsflGdcWPPmV+j3fire4AwwoqHV/BibgvBmR9ZIo4s867smv+g==" + }, + "@ant-design/react-slick": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-1.0.2.tgz", + "integrity": "sha512-Wj8onxL/T8KQLFFiCA4t8eIRGpRR+UPgOdac2sYzonv+i0n3kXHmvHLLiOYL655DQx2Umii9Y9nNgL7ssu5haQ==", + "requires": { + "@babel/runtime": "^7.10.4", + "classnames": "^2.2.5", + "json2mq": "^0.2.0", + "resize-observer-polyfill": "^1.5.1", + "throttle-debounce": "^5.0.0" + } + }, + "@apideck/better-ajv-errors": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", + "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", + "requires": { + "json-schema": "^0.4.0", + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + } + }, + "@babel/code-frame": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "requires": { + "@babel/highlight": "^7.22.5" + } + }, + "@babel/compat-data": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz", + "integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==" + }, + "@babel/core": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", + "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helpers": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + } + }, + "@babel/eslint-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.22.5.tgz", + "integrity": "sha512-C69RWYNYtrgIRE5CmTd77ZiLDXqgBipahJc/jHP3sLcAGj6AJzxNIuKNpVnICqbyK7X3pFUfEvL++rvtbQpZkQ==", + "requires": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + } + } + }, + "@babel/generator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz", + "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==", + "requires": { + "@babel/types": "^7.22.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz", + "integrity": "sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz", + "integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==", + "requires": { + "@babel/compat-data": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.5.tgz", + "integrity": "sha512-xkb58MyOYIslxu3gKmVXmjTtUPvBU4odYzbiIQbWwLKIHCsx6UGZGX6F1IznMFVnDdirseUZopzN+ZRt8Xb33Q==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "semver": "^6.3.0" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.5.tgz", + "integrity": "sha512-1VpEFOIbMRaXyDeUwUfmTIxExLwQ+zkW+Bh5zXpApA3oQedBx9v/updixWxnx/bZpKw7u8VxWjb/qWpIcmPq8A==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.0" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.0.tgz", + "integrity": "sha512-RnanLx5ETe6aybRi1cO/edaRH+bNYWaryCEmjDDYyNr4wnSzyOp8T0dWipmqVHKEY3AbVKUom50AKSlj1zmKbg==", + "requires": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" + }, + "@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "requires": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz", + "integrity": "sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-transforms": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz", + "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.5.tgz", + "integrity": "sha512-cU0Sq1Rf4Z55fgz7haOakIyM7+x/uCFwXpLPaeRzfoUtAEAuUZjZvFPjL/rk5rW693dIgn2hng1W7xbT7lWT4g==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-wrap-function": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-replace-supers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.5.tgz", + "integrity": "sha512-aLdNM5I3kdI/V9xGNyKSF3X/gTyMUBohTZ+/3QdQKAA9vxIiy12E+8E2HoOP1/DjeqU+g6as35QHJNMDDYpuCg==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", + "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" + }, + "@babel/helper-validator-identifier": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==" + }, + "@babel/helper-validator-option": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==" + }, + "@babel/helper-wrap-function": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.5.tgz", + "integrity": "sha512-bYqLIBSEshYcYQyfks8ewYA8S30yaGSeRslcvKMvoUk6HHPySbxHq9YRi6ghhzEU+yhQv9bP/jXnygkStOcqZw==", + "requires": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/helpers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz", + "integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==", + "requires": { + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/highlight": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "requires": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz", + "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==" + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz", + "integrity": "sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz", + "integrity": "sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.5" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.22.5.tgz", + "integrity": "sha512-h8hlezQ4dl6ixodgXkH8lUfcD7x+WAuIqPUjwGoItynrXOAv4a4Tci1zA/qjzQjjcl0v3QpLdc2LM6ZACQuY7A==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/plugin-syntax-decorators": "^7.22.5" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-decorators": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.22.5.tgz", + "integrity": "sha512-avpUOBS7IU6al8MmF1XpAyj9QYeLPuSDJI5D4pVMSMdL7xQokKqJPYQC67RCT0aCTashUXPiGwMJ0DEXXCEmMA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-flow": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.22.5.tgz", + "integrity": "sha512-9RdCl0i+q0QExayk2nOS7853w08yLucnnPML6EN9S8fgMPVtdLDCdx/cOQ/i44Lb9UeQX9A35yaqBBOMMZxPxQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", + "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-import-attributes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz", + "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", + "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-async-generator-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.5.tgz", + "integrity": "sha512-gGOEvFzm3fWoyD5uZq7vVTD57pPJ3PczPUD/xCFGjzBpUosnklmXyKnGQbbbGs1NPNPskFex0j93yKbHt0cHyg==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", + "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", + "requires": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", + "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz", + "integrity": "sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-class-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz", + "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-class-static-block": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz", + "integrity": "sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.5.tgz", + "integrity": "sha512-2edQhLfibpWpsVBx2n/GKOz6JdGQvLruZQfGr9l1qes2KQaWswjBzhQF7UDUZMNaMMQeYnQzxwOMPsbYF7wqPQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + } + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", + "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.5" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz", + "integrity": "sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz", + "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz", + "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-dynamic-import": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz", + "integrity": "sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz", + "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-export-namespace-from": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz", + "integrity": "sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.22.5.tgz", + "integrity": "sha512-tujNbZdxdG0/54g/oua8ISToaXTFBf8EnSb5PgQSciIXWOWKX3S4+JR7ZE9ol8FZwf9kxitzkGQ+QWeov/mCiA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-flow": "^7.22.5" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz", + "integrity": "sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", + "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", + "requires": { + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-json-strings": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz", + "integrity": "sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", + "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-logical-assignment-operators": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz", + "integrity": "sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", + "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz", + "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==", + "requires": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz", + "integrity": "sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==", + "requires": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz", + "integrity": "sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ==", + "requires": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz", + "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==", + "requires": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz", + "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz", + "integrity": "sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-transform-numeric-separator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz", + "integrity": "sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-transform-object-rest-spread": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz", + "integrity": "sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ==", + "requires": { + "@babel/compat-data": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.22.5" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", + "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5" + } + }, + "@babel/plugin-transform-optional-catch-binding": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz", + "integrity": "sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-transform-optional-chaining": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.5.tgz", + "integrity": "sha512-AconbMKOMkyG+xCng2JogMCDcqW8wedQAqpVIL4cOSescZ7+iW8utC6YDZLMCSUIReEA733gzRSaOSXMAt/4WQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz", + "integrity": "sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-private-methods": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz", + "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-private-property-in-object": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz", + "integrity": "sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", + "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-react-constant-elements": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.22.5.tgz", + "integrity": "sha512-BF5SXoO+nX3h5OhlN78XbbDrBOffv+AxPP2ENaJOVqjWCgBDeOY3WcaUcddutGSfoap+5NEQ/q/4I3WZIvgkXA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz", + "integrity": "sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.5.tgz", + "integrity": "sha512-rog5gZaVbUip5iWDMTYbVM15XQq+RkUKhET/IHR6oizR+JEoN6CAfTTuHcK4vwUyzca30qqHqEpzBOnaRMWYMA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "requires": { + "@babel/plugin-transform-react-jsx": "^7.22.5" + } + }, + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.22.5.tgz", + "integrity": "sha512-gP4k85wx09q+brArVinTXhWiyzLl9UpmGva0+mWyKxk6JZequ05x3eUcIUE+FyttPKJFRRVtAvQaJ6YF9h1ZpA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz", + "integrity": "sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.1" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz", + "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.5.tgz", + "integrity": "sha512-bg4Wxd1FWeFx3daHFTWk1pkSWK/AyQuiyAoeZAOkAOUBjnZPH6KT7eMxouV47tQ6hl6ax2zyAWBdWZXbrvXlaw==", + "requires": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.3", + "babel-plugin-polyfill-corejs3": "^0.8.1", + "babel-plugin-polyfill-regenerator": "^0.5.0", + "semver": "^6.3.0" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", + "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", + "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz", + "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", + "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz", + "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.5.tgz", + "integrity": "sha512-SMubA9S7Cb5sGSFFUlqxyClTA9zWJ8qGQrppNUm05LtFuN1ELRFNndkix4zUJrC9F+YivWwa1dHMSyo0e0N9dA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-typescript": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz", + "integrity": "sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-property-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz", + "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz", + "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-sets-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz", + "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/preset-env": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.5.tgz", + "integrity": "sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A==", + "requires": { + "@babel/compat-data": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.5", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.5", + "@babel/plugin-transform-async-to-generator": "^7.22.5", + "@babel/plugin-transform-block-scoped-functions": "^7.22.5", + "@babel/plugin-transform-block-scoping": "^7.22.5", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-class-static-block": "^7.22.5", + "@babel/plugin-transform-classes": "^7.22.5", + "@babel/plugin-transform-computed-properties": "^7.22.5", + "@babel/plugin-transform-destructuring": "^7.22.5", + "@babel/plugin-transform-dotall-regex": "^7.22.5", + "@babel/plugin-transform-duplicate-keys": "^7.22.5", + "@babel/plugin-transform-dynamic-import": "^7.22.5", + "@babel/plugin-transform-exponentiation-operator": "^7.22.5", + "@babel/plugin-transform-export-namespace-from": "^7.22.5", + "@babel/plugin-transform-for-of": "^7.22.5", + "@babel/plugin-transform-function-name": "^7.22.5", + "@babel/plugin-transform-json-strings": "^7.22.5", + "@babel/plugin-transform-literals": "^7.22.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.22.5", + "@babel/plugin-transform-member-expression-literals": "^7.22.5", + "@babel/plugin-transform-modules-amd": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.5", + "@babel/plugin-transform-modules-systemjs": "^7.22.5", + "@babel/plugin-transform-modules-umd": "^7.22.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.22.5", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.5", + "@babel/plugin-transform-numeric-separator": "^7.22.5", + "@babel/plugin-transform-object-rest-spread": "^7.22.5", + "@babel/plugin-transform-object-super": "^7.22.5", + "@babel/plugin-transform-optional-catch-binding": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.5", + "@babel/plugin-transform-parameters": "^7.22.5", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.5", + "@babel/plugin-transform-property-literals": "^7.22.5", + "@babel/plugin-transform-regenerator": "^7.22.5", + "@babel/plugin-transform-reserved-words": "^7.22.5", + "@babel/plugin-transform-shorthand-properties": "^7.22.5", + "@babel/plugin-transform-spread": "^7.22.5", + "@babel/plugin-transform-sticky-regex": "^7.22.5", + "@babel/plugin-transform-template-literals": "^7.22.5", + "@babel/plugin-transform-typeof-symbol": "^7.22.5", + "@babel/plugin-transform-unicode-escapes": "^7.22.5", + "@babel/plugin-transform-unicode-property-regex": "^7.22.5", + "@babel/plugin-transform-unicode-regex": "^7.22.5", + "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.3", + "babel-plugin-polyfill-corejs3": "^0.8.1", + "babel-plugin-polyfill-regenerator": "^0.5.0", + "core-js-compat": "^3.30.2", + "semver": "^6.3.0" + }, + "dependencies": { + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "requires": {} + } + } + }, + "@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/preset-react": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.22.5.tgz", + "integrity": "sha512-M+Is3WikOpEJHgR385HbuCITPTaPRaNkibTEa9oiofmJvIsrceb4yp9RL9Kb+TE8LznmeyZqpP+Lopwcx59xPQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-transform-react-display-name": "^7.22.5", + "@babel/plugin-transform-react-jsx": "^7.22.5", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.22.5" + } + }, + "@babel/preset-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.22.5.tgz", + "integrity": "sha512-YbPaal9LxztSGhmndR46FmAbkJ/1fAsw293tSU+I5E5h+cnJ3d4GTwyUgGYmOXJYdGA+uNePle4qbaRzj2NISQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.5", + "@babel/plugin-transform-typescript": "^7.22.5" + } + }, + "@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "@babel/runtime": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", + "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "requires": { + "regenerator-runtime": "^0.14.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + } + } + }, + "@babel/template": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "requires": { + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/traverse": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz", + "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==", + "requires": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + } + } + }, + "@babel/types": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", + "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + }, + "@csstools/normalize.css": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", + "integrity": "sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==" + }, + "@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "requires": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + } + }, + "@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "requires": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + } + }, + "@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "requires": {} + }, + "@csstools/selector-specificity": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", + "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "requires": {} + }, + "@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==" + }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==" + }, + "@eslint/eslintrc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.2", + "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" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + } + } + }, + "@eslint/js": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz", + "integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==" + }, + "@humanwhocodes/config-array": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==" + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==" + }, + "@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "@jest/core": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "requires": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "@jest/environment": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "requires": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "@jest/expect-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", + "requires": { + "jest-get-type": "^29.4.3" + } + }, + "@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "requires": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "requires": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==" + }, + "expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "requires": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + } + }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==" + }, + "jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + } + } + }, + "@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@jest/schemas": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "requires": { + "@sinclair/typebox": "^0.25.16" + } + }, + "@jest/source-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "requires": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "@jest/test-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "requires": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + } + }, + "@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@jest/types": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", + "requires": { + "@jest/schemas": "^29.4.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + }, + "@jridgewell/source-map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", + "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + }, + "dependencies": { + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + } + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "optional": true, + "requires": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "optional": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + } + } + }, + "@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "requires": { + "eslint-scope": "5.1.1" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + } + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz", + "integrity": "sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==", + "requires": { + "ansi-html-community": "^0.0.8", + "common-path-prefix": "^3.0.0", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "find-up": "^5.0.0", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^3.0.0", + "source-map": "^0.7.3" + } + }, + "@rc-component/color-picker": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-1.5.1.tgz", + "integrity": "sha512-onyAFhWKXuG4P162xE+7IgaJkPkwM94XlOYnQuu69XdXWMfxpeFi6tpJBsieIMV7EnyLV5J3lDzdLiFeK0iEBA==", + "requires": { + "@babel/runtime": "^7.23.6", + "@ctrl/tinycolor": "^3.6.1", + "classnames": "^2.2.6", + "rc-util": "^5.38.1" + } + }, + "@rc-component/context": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz", + "integrity": "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==", + "requires": { + "@babel/runtime": "^7.10.1", + "rc-util": "^5.27.0" + } + }, + "@rc-component/mini-decimal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz", + "integrity": "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==", + "requires": { + "@babel/runtime": "^7.18.0" + } + }, + "@rc-component/mutate-observer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz", + "integrity": "sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==", + "requires": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + } + }, + "@rc-component/portal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz", + "integrity": "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==", + "requires": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + } + }, + "@rc-component/tour": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.12.3.tgz", + "integrity": "sha512-U4mf1FiUxGCwrX4ed8op77Y8VKur+8Y/61ylxtqGbcSoh1EBC7bWd/DkLu0ClTUrKZInqEi1FL7YgFtnT90vHA==", + "requires": { + "@babel/runtime": "^7.18.0", + "@rc-component/portal": "^1.0.0-9", + "@rc-component/trigger": "^1.3.6", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + } + }, + "@rc-component/trigger": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-1.18.2.tgz", + "integrity": "sha512-jRLYgFgjLEPq3MvS87fIhcfuywFSRDaDrYw1FLku7Cm4esszvzTbA0JBsyacAyLrK9rF3TiHFcvoEDMzoD3CTA==", + "requires": { + "@babel/runtime": "^7.23.2", + "@rc-component/portal": "^1.1.0", + "classnames": "^2.3.2", + "rc-motion": "^2.0.0", + "rc-resize-observer": "^1.3.1", + "rc-util": "^5.38.0" + } + }, + "@react-dnd/asap": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", + "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==" + }, + "@react-dnd/invariant": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz", + "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==" + }, + "@react-dnd/shallowequal": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", + "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" + }, + "@react-pdf-viewer/attachment": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/attachment/-/attachment-3.12.0.tgz", + "integrity": "sha512-mhwrYJSIpCvHdERpLUotqhMgSjhtF+BTY1Yb9Fnzpcq3gLZP+Twp5Rynq21tCrVdDizPaVY7SKu400GkgdMfZw==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/bookmark": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/bookmark/-/bookmark-3.12.0.tgz", + "integrity": "sha512-i7nEit8vIFMAES8RFGwprZ9cXOOZb9ZStPW6E6yuObJEXcvBj/ctsbBJGZxqUZOGklM0JoB7sjHyxAriHfe92A==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/core": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/core/-/core-3.12.0.tgz", + "integrity": "sha512-8MsdlQJ4jaw3GT+zpCHS33nwnvzpY0ED6DEahZg9WngG++A5RMhk8LSlxdHelwaFFHFiXBjmOaj2Kpxh50VQRg==", + "requires": {} + }, + "@react-pdf-viewer/default-layout": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/default-layout/-/default-layout-3.12.0.tgz", + "integrity": "sha512-K2fS4+TJynHxxCBFuIDiFuAw3nqOh4bkBgtVZ/2pGvnFn9lLg46YGLMnTXCQqtyZzzXYh696jmlFViun3is4pA==", + "requires": { + "@react-pdf-viewer/attachment": "3.12.0", + "@react-pdf-viewer/bookmark": "3.12.0", + "@react-pdf-viewer/core": "3.12.0", + "@react-pdf-viewer/thumbnail": "3.12.0", + "@react-pdf-viewer/toolbar": "3.12.0" + } + }, + "@react-pdf-viewer/full-screen": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/full-screen/-/full-screen-3.12.0.tgz", + "integrity": "sha512-hQouJ26QUaRBCXNMU1aI1zpJn4l4PJRvlHhuE2dZYtLl37ycjl7vBCQYZW1FwnuxMWztZsY47R43DKaZORg0pg==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/get-file": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/get-file/-/get-file-3.12.0.tgz", + "integrity": "sha512-Uhq45n2RWlZ7Ec/BtBJ0WQESRciaYIltveDXHNdWvXgFdOS8XsvB+mnTh/wzm7Cfl9hpPyzfeezifdU9AkQgQg==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/open": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/open/-/open-3.12.0.tgz", + "integrity": "sha512-vhiDEYsiQLxvZkIKT9VPYHZ1BOnv46x9eCEmRWxO1DJ8fa/GRDTA9ivXmq/ap0dGEJs6t+epleCkCEfllLR/Yw==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/page-navigation": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/page-navigation/-/page-navigation-3.12.0.tgz", + "integrity": "sha512-tVEJ48Dd5kajV1nKkrPWijglJRNBiKBTyYDKVexhiRdTHUP1f6QQXiSyDgCUb0IGSZeJzOJb1h7ApKHe8OTtuw==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/print": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/print/-/print-3.12.0.tgz", + "integrity": "sha512-xJn76CgbU/M2iNaN7wLHTg+sdOekkRMfCakFLwPrE+SR7qD6NUF4vQQKJBSVCCK5bUijzb6cWfKGfo8VA72o4Q==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/properties": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/properties/-/properties-3.12.0.tgz", + "integrity": "sha512-dYTCHtVwFNkpDo7QxL2qk/8zAKndLwdD1FFxBftl6jIlQbtvNdxkFfkv1HcQING9Ic+7DBryOiD7W0ze4IERYg==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/rotate": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/rotate/-/rotate-3.12.0.tgz", + "integrity": "sha512-yaxaMYPChvNOjR8+AxRmj0kvojyJKPq4XHEcIB2lJJgBY1Zra3mliDUP3Nlb4yV8BS9+yBqWn9U9mtnopQD+tw==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/scroll-mode": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/scroll-mode/-/scroll-mode-3.12.0.tgz", + "integrity": "sha512-okII7Xqhl6cMvl1izdEvlXNJ+vJVq/qdg53hJIDYVgBCWskLk/cpjUg/ZonBxseG9lIDP3w2VO1McT8Gn11OAg==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/search": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/search/-/search-3.12.0.tgz", + "integrity": "sha512-jAkLpis49fsDDY/HrbUZIOIhzF5vynONQNA4INQKI38r/MjveblrkNv7qbr9j5lQ/WFic5+gD1e+Mtpf1/7DiA==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/selection-mode": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/selection-mode/-/selection-mode-3.12.0.tgz", + "integrity": "sha512-yysWEu2aCtBvzSgbhgI9kT5cq2hf0FU6Z+3B7MMXz14Kxyc3y18wUqxtgbvpFEfWF0bNUUq16JtWRljtxvZ83w==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/theme": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/theme/-/theme-3.12.0.tgz", + "integrity": "sha512-cdBi+wR1VOZ6URCcO9plmAZQu4ZGFcd7HJdBe7VIFiGyrvl9I/Of74ONLycnDImSuONt8D3uNjPBLieeaShVeg==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/thumbnail": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/thumbnail/-/thumbnail-3.12.0.tgz", + "integrity": "sha512-Vc8j3bO6wumWZV4o6pAbktPWKDSC9tQAzOCJ3cof541u4i44C11ccYC4W9aNcsMMUSO3bNwAGWtP8OFthV5akQ==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@react-pdf-viewer/toolbar": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/toolbar/-/toolbar-3.12.0.tgz", + "integrity": "sha512-qACTU3qXHgtNK8J+T13EWio+0liilj86SJ87BdapqXynhl720OKPlSKOQqskUGqg3oTUJAhrse9XG6SFdHJx+g==", + "requires": { + "@react-pdf-viewer/core": "3.12.0", + "@react-pdf-viewer/full-screen": "3.12.0", + "@react-pdf-viewer/get-file": "3.12.0", + "@react-pdf-viewer/open": "3.12.0", + "@react-pdf-viewer/page-navigation": "3.12.0", + "@react-pdf-viewer/print": "3.12.0", + "@react-pdf-viewer/properties": "3.12.0", + "@react-pdf-viewer/rotate": "3.12.0", + "@react-pdf-viewer/scroll-mode": "3.12.0", + "@react-pdf-viewer/search": "3.12.0", + "@react-pdf-viewer/selection-mode": "3.12.0", + "@react-pdf-viewer/theme": "3.12.0", + "@react-pdf-viewer/zoom": "3.12.0" + } + }, + "@react-pdf-viewer/zoom": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/zoom/-/zoom-3.12.0.tgz", + "integrity": "sha512-V0GUTyPM77+LzhoKX+T3XI10/HfGdqRTbgeP7ID60FCzcwu6kXWqJn5tzabjDKLTlFv8mJmn0aa/ppkIU97nfA==", + "requires": { + "@react-pdf-viewer/core": "3.12.0" + } + }, + "@remix-run/router": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.6.3.tgz", + "integrity": "sha512-EXJysQ7J3veRECd0kZFQwYYd5sJMcq2O/m60zu1W2l3oVQ9xtub8jTOtYRE0+M2iomyG/W3Ps7+vp2kna0C27Q==" + }, + "@rjsf/antd": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@rjsf/antd/-/antd-5.16.1.tgz", + "integrity": "sha512-bgv1wY44AxygeCrG31Rv9KtXz/R/vsD8PbSm9lyR4VwnqWPDiOSQCo0PyLHaS+hecU02bkR8D8+sCVZqeldolg==", + "requires": { + "classnames": "^2.5.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "rc-picker": "^2.7.6" + } + }, + "@rjsf/core": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@rjsf/core/-/core-5.16.1.tgz", + "integrity": "sha512-zIqm5aJ0CfpqsJXcJvIEoYZMfPa6hLqKSeOwwifuHSjznC6fbXPdmqnifBCPVy0GgMaDDWekZLfndk5W3ZO1YA==", + "requires": { + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "markdown-to-jsx": "^7.4.0", + "nanoid": "^3.3.7", + "prop-types": "^15.8.1" + } + }, + "@rjsf/utils": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.16.1.tgz", + "integrity": "sha512-zJ8WopscMl46QBjlIalIoPERs7kgSfUwIZ5zx4OMBRp0O+m7Scx0F+4iHqLnRuHEfaCNA5D7IKxmx1whOG/x1Q==", + "requires": { + "json-schema-merge-allof": "^0.8.1", + "jsonpointer": "^5.0.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "react-is": "^18.2.0" + } + }, + "@rjsf/validator-ajv8": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-5.8.1.tgz", + "integrity": "sha512-ImMd8nZeQzgt26y90yqEmiD7XPtDCX4LYGfniCr/PeAOk79OKhcdv8OMsdGTh9pGPtHy1qOJvntALKOpHGAeYg==", + "requires": { + "ajv": "^8.12.0", + "ajv-formats": "^2.1.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21" + } + }, + "@rollup/plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", + "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + } + }, + "@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "requires": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "dependencies": { + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "requires": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "dependencies": { + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + } + } + }, + "@rushstack/eslint-patch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.2.tgz", + "integrity": "sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==" + }, + "@sinclair/typebox": { + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==" + }, + "@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, + "@surma/rollup-plugin-off-main-thread": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", + "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "requires": { + "ejs": "^3.1.6", + "json5": "^2.2.0", + "magic-string": "^0.25.0", + "string.prototype.matchall": "^4.0.6" + } + }, + "@svgr/babel-plugin-add-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==" + }, + "@svgr/babel-plugin-remove-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==" + }, + "@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", + "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==" + }, + "@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", + "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==" + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", + "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==" + }, + "@svgr/babel-plugin-svg-em-dimensions": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", + "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==" + }, + "@svgr/babel-plugin-transform-react-native-svg": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", + "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==" + }, + "@svgr/babel-plugin-transform-svg-component": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", + "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==" + }, + "@svgr/babel-preset": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", + "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", + "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", + "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", + "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", + "@svgr/babel-plugin-transform-svg-component": "^5.5.0" + } + }, + "@svgr/core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", + "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", + "requires": { + "@svgr/plugin-jsx": "^5.5.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.0" + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", + "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", + "requires": { + "@babel/types": "^7.12.6" + } + }, + "@svgr/plugin-jsx": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", + "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", + "requires": { + "@babel/core": "^7.12.3", + "@svgr/babel-preset": "^5.5.0", + "@svgr/hast-util-to-babel-ast": "^5.5.0", + "svg-parser": "^2.0.2" + } + }, + "@svgr/plugin-svgo": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", + "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", + "requires": { + "cosmiconfig": "^7.0.0", + "deepmerge": "^4.2.2", + "svgo": "^1.2.2" + } + }, + "@svgr/webpack": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", + "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", + "requires": { + "@babel/core": "^7.12.3", + "@babel/plugin-transform-react-constant-elements": "^7.12.1", + "@babel/preset-env": "^7.12.1", + "@babel/preset-react": "^7.12.5", + "@svgr/core": "^5.5.0", + "@svgr/plugin-jsx": "^5.5.0", + "@svgr/plugin-svgo": "^5.5.0", + "loader-utils": "^2.0.0" + } + }, + "@testing-library/dom": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz", + "integrity": "sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w==", + "peer": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + } + }, + "@testing-library/jest-dom": { + "version": "5.16.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", + "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", + "requires": { + "@adobe/css-tools": "^4.0.1", + "@babel/runtime": "^7.9.2", + "@types/testing-library__jest-dom": "^5.9.1", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@testing-library/react": { + "version": "13.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", + "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", + "requires": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^8.5.0", + "@types/react-dom": "^18.0.0" + }, + "dependencies": { + "@testing-library/dom": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz", + "integrity": "sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "^5.0.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.4.4", + "pretty-format": "^27.0.2" + } + } + } + }, + "@testing-library/user-event": { + "version": "13.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", + "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", + "requires": { + "@babel/runtime": "^7.12.5" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" + }, + "@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" + }, + "@types/aria-query": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" + }, + "@types/babel__core": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", + "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "requires": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", + "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", + "requires": { + "@babel/types": "^7.20.7" + } + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", + "integrity": "sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig==", + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/debug": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", + "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", + "requires": { + "@types/ms": "*" + } + }, + "@types/eslint": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.40.2.tgz", + "integrity": "sha512-PRVjQ4Eh9z9pmmtaq8nTjZjQwKFk7YIHIud3lRoKRBgUQjgjRmoGxxGEPXQkF+lH7QkHJRNr5F4aBgYCW0lqpQ==", + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" + }, + "@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.35", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", + "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "requires": { + "@types/node": "*" + } + }, + "@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "@types/http-proxy": { + "version": "1.17.11", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", + "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "29.5.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.2.tgz", + "integrity": "sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg==", + "requires": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + } + } + }, + "@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==" + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" + }, + "@types/mdast": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.12.tgz", + "integrity": "sha512-DT+iNIRNX884cx0/Q1ja7NyUPpZuv0KPyL5rGNxm1WC1OtHstl7n4Jb7nk+xacNShQMbczJjt8uFzznpp6kYBg==", + "requires": { + "@types/unist": "^2" + } + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, + "@types/node": { + "version": "20.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", + "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==" + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==" + }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "@types/q": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", + "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "@types/react": { + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.12.tgz", + "integrity": "sha512-ndmBMLCgn38v3SntMeoJaIrO6tGHYKMEBohCUmw8HoLLQdRMOIGXfeYaBTLe2lsFaSB3MOK1VXscYFnmLtTSmw==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.5.tgz", + "integrity": "sha512-sRQsOS/sCLnpQhR4DSKGTtWFE3FZjpQa86KPVbhUqdYMRZ9FEFcfAytKhR/vUG2rH1oFbOOej6cuD7MFSobDRQ==", + "requires": { + "@types/react": "*" + } + }, + "@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "requires": { + "@types/node": "*" + } + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "@types/scheduler": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" + }, + "@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==" + }, + "@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "requires": { + "@types/node": "*" + } + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" + }, + "@types/testing-library__jest-dom": { + "version": "5.14.6", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.6.tgz", + "integrity": "sha512-FkHXCb+ikSoUP4Y4rOslzTdX5sqYwMxfefKh1GmZ8ce1GOkEHntSp6b5cGadmNfp5e4BMEWOMx+WSKd5/MqlDA==", + "requires": { + "@types/jest": "*" + } + }, + "@types/trusted-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", + "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==" + }, + "@types/unist": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.7.tgz", + "integrity": "sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==" + }, + "@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "requires": { + "@types/node": "*" + } + }, + "@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.11.tgz", + "integrity": "sha512-XxuOfTkCUiOSyBWIvHlUraLw/JT/6Io1365RO6ZuI88STKMavJZPNMU0lFcUTeQXEhHiv64CbxYxBNoDVSmghg==", + "requires": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.59.11", + "@typescript-eslint/type-utils": "5.59.11", + "@typescript-eslint/utils": "5.59.11", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.59.11.tgz", + "integrity": "sha512-GkQGV0UF/V5Ra7gZMBmiD1WrYUFOJNvCZs+XQnUyJoxmqfWMXVNyB2NVCPRKefoQcpvTv9UpJyfCvsJFs8NzzQ==", + "requires": { + "@typescript-eslint/utils": "5.59.11" + } + }, + "@typescript-eslint/parser": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.11.tgz", + "integrity": "sha512-s9ZF3M+Nym6CAZEkJJeO2TFHHDsKAM3ecNkLuH4i4s8/RCPnF5JRip2GyviYkeEAcwGMJxkqG9h2dAsnA1nZpA==", + "requires": { + "@typescript-eslint/scope-manager": "5.59.11", + "@typescript-eslint/types": "5.59.11", + "@typescript-eslint/typescript-estree": "5.59.11", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.11.tgz", + "integrity": "sha512-dHFOsxoLFtrIcSj5h0QoBT/89hxQONwmn3FOQ0GOQcLOOXm+MIrS8zEAhs4tWl5MraxCY3ZJpaXQQdFMc2Tu+Q==", + "requires": { + "@typescript-eslint/types": "5.59.11", + "@typescript-eslint/visitor-keys": "5.59.11" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.11.tgz", + "integrity": "sha512-LZqVY8hMiVRF2a7/swmkStMYSoXMFlzL6sXV6U/2gL5cwnLWQgLEG8tjWPpaE4rMIdZ6VKWwcffPlo1jPfk43g==", + "requires": { + "@typescript-eslint/typescript-estree": "5.59.11", + "@typescript-eslint/utils": "5.59.11", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.11.tgz", + "integrity": "sha512-epoN6R6tkvBYSc+cllrz+c2sOFWkbisJZWkOE+y3xHtvYaOE6Wk6B8e114McRJwFRjGvYdJwLXQH5c9osME/AA==" + }, + "@typescript-eslint/typescript-estree": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.11.tgz", + "integrity": "sha512-YupOpot5hJO0maupJXixi6l5ETdrITxeo5eBOeuV7RSKgYdU3G5cxO49/9WRnJq9EMrB7AuTSLH/bqOsXi7wPA==", + "requires": { + "@typescript-eslint/types": "5.59.11", + "@typescript-eslint/visitor-keys": "5.59.11", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "@typescript-eslint/utils": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.11.tgz", + "integrity": "sha512-didu2rHSOMUdJThLk4aZ1Or8IcO3HzCw/ZvEjTTIfjIrcdd5cvSIwwDy2AOlE7htSNp7QIZ10fLMyRCveesMLg==", + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.59.11", + "@typescript-eslint/types": "5.59.11", + "@typescript-eslint/typescript-estree": "5.59.11", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.59.11", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.11.tgz", + "integrity": "sha512-KGYniTGG3AMTuKF9QBD7EIrvufkB6O6uX3knP73xbKLMpH+QRPcgnCxjWXSHjMRuOxFLovljqQgQpR0c7GvjoA==", + "requires": { + "@typescript-eslint/types": "5.59.11", + "eslint-visitor-keys": "^3.3.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "requires": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==" + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "optional": true + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==" + }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + } + } + }, + "acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "requires": {} + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "requires": {} + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" + }, + "address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==" + }, + "adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "requires": { + "ajv": "^8.0.0" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + } + } + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==" + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "antd": { + "version": "5.13.2", + "resolved": "https://registry.npmjs.org/antd/-/antd-5.13.2.tgz", + "integrity": "sha512-P+N8gc0NOPy2WqJj/57Ey3dZUmb7nEUwAM+CIJaR5SOEjZnhEtMGRJSt+3lnhJ3MNRR39aR6NYkRVp2mYfphiA==", + "requires": { + "@ant-design/colors": "^7.0.2", + "@ant-design/cssinjs": "^1.18.2", + "@ant-design/icons": "^5.2.6", + "@ant-design/react-slick": "~1.0.2", + "@ctrl/tinycolor": "^3.6.1", + "@rc-component/color-picker": "~1.5.1", + "@rc-component/mutate-observer": "^1.1.0", + "@rc-component/tour": "~1.12.2", + "@rc-component/trigger": "^1.18.2", + "classnames": "^2.5.1", + "copy-to-clipboard": "^3.3.3", + "dayjs": "^1.11.10", + "qrcode.react": "^3.1.0", + "rc-cascader": "~3.21.0", + "rc-checkbox": "~3.1.0", + "rc-collapse": "~3.7.2", + "rc-dialog": "~9.3.4", + "rc-drawer": "~7.0.0", + "rc-dropdown": "~4.1.0", + "rc-field-form": "~1.41.0", + "rc-image": "~7.5.1", + "rc-input": "~1.4.3", + "rc-input-number": "~8.6.1", + "rc-mentions": "~2.10.1", + "rc-menu": "~9.12.4", + "rc-motion": "^2.9.0", + "rc-notification": "~5.3.0", + "rc-pagination": "~4.0.4", + "rc-picker": "~3.14.6", + "rc-progress": "~3.5.1", + "rc-rate": "~2.12.0", + "rc-resize-observer": "^1.4.0", + "rc-segmented": "~2.2.2", + "rc-select": "~14.11.0", + "rc-slider": "~10.5.0", + "rc-steps": "~6.0.1", + "rc-switch": "~4.1.0", + "rc-table": "~7.37.0", + "rc-tabs": "~14.0.0", + "rc-textarea": "~1.6.3", + "rc-tooltip": "~6.1.3", + "rc-tree": "~5.8.2", + "rc-tree-select": "~5.17.0", + "rc-upload": "~4.5.2", + "rc-util": "^5.38.1", + "scroll-into-view-if-needed": "^3.1.0", + "throttle-debounce": "^5.0.0" + }, + "dependencies": { + "rc-picker": { + "version": "3.14.6", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-3.14.6.tgz", + "integrity": "sha512-AdKKW0AqMwZsKvIpwUWDUnpuGKZVrbxVTZTNjcO+pViGkjC1EBcjMgxVe8tomOEaIHJL5Gd13vS8Rr3zzxWmag==", + "requires": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^1.5.0", + "classnames": "^2.2.1", + "rc-util": "^5.30.0" + } + } + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "optional": true + }, + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "requires": { + "deep-equal": "^2.0.5" + } + }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + } + }, + "array-tree-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz", + "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==" + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.reduce": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", + "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + } + }, + "array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" + }, + "async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "autoprefixer": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "requires": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, + "axe-core": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz", + "integrity": "sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==" + }, + "axios": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "requires": { + "dequal": "^2.0.3" + } + }, + "babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "requires": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "babel-loader": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz", + "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==", + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "requires": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "dependencies": { + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "babel-plugin-named-asset-import": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", + "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", + "requires": {} + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.3.tgz", + "integrity": "sha512-bM3gHc337Dta490gg+/AseNB9L4YLHxq1nGKZZSHbhXv4aTYU2MD2cjza1Ru4S6975YLTaL1K8uJf6ukJhhmtw==", + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.4.0", + "semver": "^6.1.1" + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.1.tgz", + "integrity": "sha512-ikFrZITKg1xH6pLND8zT14UPgjKHiGLqex7rGEZCH2EvhsneJaJPemmpQaIZV5AL03II+lXylw3UmddDK8RU5Q==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.4.0", + "core-js-compat": "^3.30.1" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.0.tgz", + "integrity": "sha512-hDJtKjMLVa7Z+LwnTCxoDLQj6wdc+B8dun7ayF2fYieI6OzfuvcLMB32ihJZ4UhCBwNYGl5bg/x/P9cMdnkc2g==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.4.0" + } + }, + "babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==" + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "requires": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "babel-preset-react-app": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz", + "integrity": "sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==", + "requires": { + "@babel/core": "^7.16.0", + "@babel/plugin-proposal-class-properties": "^7.16.0", + "@babel/plugin-proposal-decorators": "^7.16.4", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", + "@babel/plugin-proposal-numeric-separator": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.0", + "@babel/plugin-proposal-private-methods": "^7.16.0", + "@babel/plugin-transform-flow-strip-types": "^7.16.0", + "@babel/plugin-transform-react-display-name": "^7.16.0", + "@babel/plugin-transform-runtime": "^7.16.4", + "@babel/preset-env": "^7.16.4", + "@babel/preset-react": "^7.16.0", + "@babel/preset-typescript": "^7.16.0", + "@babel/runtime": "^7.16.3", + "babel-plugin-macros": "^3.1.0", + "babel-plugin-transform-react-remove-prop-types": "^0.4.24" + } + }, + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "bfj": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", + "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", + "requires": { + "bluebird": "^3.5.5", + "check-types": "^11.1.1", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "bonjour-service": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "requires": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" + }, + "browserslist": { + "version": "4.21.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.8.tgz", + "integrity": "sha512-j+7xYe+v+q2Id9qbBeCI8WX5NmZSRe8es1+0xntD/+gaWXznP8tFEkv5IgSaHf5dS1YwVMbX/4W6m937mj+wQw==", + "requires": { + "caniuse-lite": "^1.0.30001502", + "electron-to-chromium": "^1.4.428", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001503", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz", + "integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==" + }, + "canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "optional": true, + "requires": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + } + }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==" + }, + "ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==" + }, + "character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==" + }, + "check-types": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.2.tgz", + "integrity": "sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA==" + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.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" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "optional": true + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" + }, + "ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==" + }, + "cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" + }, + "classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, + "clean-css": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", + "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==" + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "optional": true + }, + "colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" + }, + "common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, + "common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "compute-gcd": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/compute-gcd/-/compute-gcd-1.2.1.tgz", + "integrity": "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==", + "requires": { + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, + "compute-lcm": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/compute-lcm/-/compute-lcm-1.1.2.tgz", + "integrity": "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==", + "requires": { + "compute-gcd": "^1.2.1", + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, + "compute-scroll-into-view": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz", + "integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" + }, + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "optional": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "requires": { + "toggle-selection": "^1.0.6" + } + }, + "core-js": { + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.31.0.tgz", + "integrity": "sha512-NIp2TQSGfR6ba5aalZD+ZQ1fSxGhDo/s1w0nx3RYzf2pnJxt7YynxFlFScP6eV7+GZsKO95NSjGxyJsU3DZgeQ==" + }, + "core-js-compat": { + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.31.0.tgz", + "integrity": "sha512-hM7YCu1cU6Opx7MXNu0NuumM0ezNeAeRKadixyiQELWY3vT3De9S4J5ZBMraWV2vZnrE1Cirl0GtFtDtMUXzPw==", + "requires": { + "browserslist": "^4.21.5" + } + }, + "core-js-pure": { + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.31.0.tgz", + "integrity": "sha512-/AnE9Y4OsJZicCzIe97JP5XoPKQJfTuEG43aEVLFJGOJpyqELod+pE6LEl63DfG1Mp8wX97LDaDpy1GmLEUxlg==" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "cron-validator": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cron-validator/-/cron-validator-1.3.1.tgz", + "integrity": "sha512-C1HsxuPCY/5opR55G5/WNzyEGDWFVG+6GLrA+fW/sCTcP6A6NTjUP2AK7B8n2PyFs90kDG2qzwm8LMheADku6A==" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" + }, + "css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "css-declaration-sorter": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", + "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", + "requires": {} + }, + "css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "css-loader": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", + "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.21", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.3", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "css-minimizer-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "requires": { + "cssnano": "^5.0.6", + "jest-worker": "^27.0.2", + "postcss": "^8.3.5", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "requires": {} + }, + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" + }, + "css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" + }, + "css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==" + }, + "cssdb": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.6.0.tgz", + "integrity": "sha512-Nna7rph8V0jC6+JBY4Vk4ndErUmfJfV6NJCaZdurL0omggabiy+QB2HCQtu5c/ACLZ0I7REv7A4QyPIoYzZx0w==" + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "requires": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + } + }, + "cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "requires": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + } + }, + "cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "requires": {} + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "requires": { + "css-tree": "^1.1.2" + }, + "dependencies": { + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + } + } + }, + "csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, + "date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "requires": { + "@babel/runtime": "^7.21.0" + } + }, + "dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" + }, + "decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "requires": { + "character-entities": "^2.0.0" + } + }, + "decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "requires": { + "mimic-response": "^2.0.0" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==" + }, + "deep-equal": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", + "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.0", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==" + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "requires": { + "execa": "^5.0.0" + } + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==" + }, + "define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "optional": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "optional": true + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==" + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==" + }, + "diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==" + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + } + }, + "dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "dnd-core": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz", + "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==", + "requires": { + "@react-dnd/asap": "^5.0.1", + "@react-dnd/invariant": "^4.0.1", + "redux": "^4.2.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" + }, + "dns-packet": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", + "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==" + }, + "dom-align": { + "version": "1.12.4", + "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.4.tgz", + "integrity": "sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==" + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==" + } + } + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "ejs": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "requires": { + "jake": "^10.8.5" + } + }, + "electron-to-chromium": { + "version": "1.4.431", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.431.tgz", + "integrity": "sha512-m232JTVmCawA2vG+1azVxhKZ9Sv1Q//xxNv5PkP5rWxGgQE8c3CiZFrh8Xnp+d1NmNxlu3QQrGIfdeW5TtXX5w==" + }, + "emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "engine.io-client": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz", + "integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + }, + "dependencies": { + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "requires": {} + } + } + }, + "engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==" + }, + "enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "requires": { + "stackframe": "^1.3.4" + } + }, + "es-abstract": { + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "requires": { + "array-buffer-byte-length": "^1.0.0", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.0", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, + "es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + } + }, + "es-module-lexer": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==" + }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, + "eslint": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz", + "integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==", + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.42.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", + "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", + "import-fresh": "^3.0.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.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + } + } + }, + "eslint-config-google": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz", + "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==", + "dev": true, + "requires": {} + }, + "eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "requires": {} + }, + "eslint-config-react-app": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", + "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", + "requires": { + "@babel/core": "^7.16.0", + "@babel/eslint-parser": "^7.16.3", + "@rushstack/eslint-patch": "^1.1.0", + "@typescript-eslint/eslint-plugin": "^5.5.0", + "@typescript-eslint/parser": "^5.5.0", + "babel-preset-react-app": "^10.0.1", + "confusing-browser-globals": "^1.0.11", + "eslint-plugin-flowtype": "^8.0.3", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jest": "^25.3.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.27.1", + "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-testing-library": "^5.0.1" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "requires": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-flowtype": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", + "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", + "requires": { + "lodash": "^4.17.21", + "string-natural-compare": "^3.0.1" + } + }, + "eslint-plugin-import": { + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "eslint-plugin-jest": { + "version": "25.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", + "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", + "requires": { + "@typescript-eslint/experimental-utils": "^5.0.0" + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", + "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", + "requires": { + "@babel/runtime": "^7.20.7", + "aria-query": "^5.1.3", + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.6.2", + "axobject-query": "^3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.3", + "language-tags": "=1.0.5", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "semver": "^6.3.0" + } + }, + "eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-plugin-react": { + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.8" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + } + } + }, + "eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "requires": {} + }, + "eslint-plugin-testing-library": { + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.0.tgz", + "integrity": "sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q==", + "requires": { + "@typescript-eslint/utils": "^5.58.0" + } + }, + "eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==" + }, + "eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "requires": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "espree": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==" + }, + "expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "requires": { + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" + } + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "requires": { + "bser": "2.1.1" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "requires": { + "flat-cache": "^3.0.4" + } + }, + "file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + } + }, + "filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "requires": { + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, + "fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "requires": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + }, + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "optional": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + } + } + }, + "fs-monkey": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz", + "integrity": "sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "optional": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "requires": { + "is-glob": "^4.0.3" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "dependencies": { + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "requires": { + "type-fest": "^0.20.2" + } + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + }, + "gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "requires": { + "duplexer": "^0.1.2" + } + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "optional": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==" + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, + "html-entities": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.6.tgz", + "integrity": "sha512-9o0+dcpIw2/HxkNuYKxSJUF/MMRZQECK4GnF+oQOmJ83yCVHTWgCH5aOXxK5bozNRmM8wtgryjHD3uloPBDEGw==" + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "requires": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + } + }, + "html-webpack-plugin": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", + "integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==", + "requires": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + } + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "requires": {} + }, + "idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" + }, + "identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", + "requires": { + "harmony-reflect": "^1.4.6" + } + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" + }, + "immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==" + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "requires": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==" + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + }, + "is-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==" + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==" + }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==" + }, + "is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" + }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==" + }, + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jake": { + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "requires": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + } + }, + "jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "requires": { + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + } + }, + "jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "requires": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "requires": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==" + }, + "expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "requires": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + } + }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==" + }, + "jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "requires": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "requires": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==" + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + } + } + }, + "jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "requires": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==" + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==" + }, + "jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "requires": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "requires": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==" + }, + "expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "requires": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + } + }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==" + }, + "jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "requires": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==" + } + } + }, + "jest-matcher-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + } + } + }, + "jest-message-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.5.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + } + } + }, + "jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "requires": {} + }, + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==" + }, + "jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "requires": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "requires": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "requires": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + } + }, + "jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==" + }, + "expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "requires": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + } + }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==" + }, + "jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "requires": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==" + } + } + }, + "jest-watch-typeahead": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-1.1.0.tgz", + "integrity": "sha512-Va5nLSJTN7YFtC2jd+7wsoe1pNe5K4ShLux/E5iHEwlB9AxaxmggY7to9KUqKojhaJw3aXqt5WAb4jGPOolpEw==", + "requires": { + "ansi-escapes": "^4.3.1", + "chalk": "^4.0.0", + "jest-regex-util": "^28.0.0", + "jest-watcher": "^28.0.0", + "slash": "^4.0.0", + "string-length": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "@jest/console": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "requires": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + } + } + }, + "@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "requires": { + "@sinclair/typebox": "^0.24.1" + } + }, + "@jest/test-result": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "requires": { + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "requires": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" + }, + "emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==" + }, + "jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + } + } + }, + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==" + }, + "jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "requires": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "jest-watcher": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "requires": { + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", + "string-length": "^4.0.1" + }, + "dependencies": { + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "requires": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" + }, + "string-length": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", + "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", + "requires": { + "char-regex": "^2.0.0", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "char-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz", + "integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==" + } + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "requires": { + "ansi-regex": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + } + } + } + } + }, + "jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "requires": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jiti": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", + "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "json-schema-compare": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/json-schema-compare/-/json-schema-compare-0.2.2.tgz", + "integrity": "sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ==", + "requires": { + "lodash": "^4.17.4" + } + }, + "json-schema-merge-allof": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz", + "integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==", + "requires": { + "compute-lcm": "^1.1.2", + "json-schema-compare": "^0.2.2", + "lodash": "^4.17.20" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + }, + "json2mq": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", + "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", + "requires": { + "string-convert": "^0.2.0" + } + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==" + }, + "jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "requires": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==" + }, + "language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" + }, + "language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "requires": { + "language-subtag-registry": "~0.3.2" + } + }, + "launch-editor": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", + "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", + "requires": { + "picocolors": "^1.0.0", + "shell-quote": "^1.7.3" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==" + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==" + }, + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "requires": { + "tslib": "^2.0.3" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==" + }, + "magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + } + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "requires": { + "tmpl": "1.0.5" + } + }, + "markdown-table": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", + "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==" + }, + "markdown-to-jsx": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.4.0.tgz", + "integrity": "sha512-zilc+MIkVVXPyTb4iIUTIz9yyqfcWjszGXnwF9K/aiBWcHXFcmdEMTkG01/oQhwSCH7SY1BnG6+ev5BzWmbPrg==", + "requires": {} + }, + "mdast-util-find-and-replace": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz", + "integrity": "sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==", + "requires": { + "@types/mdast": "^3.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==" + } + } + }, + "mdast-util-from-markdown": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", + "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + } + }, + "mdast-util-gfm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz", + "integrity": "sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg==", + "requires": { + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-gfm-autolink-literal": "^1.0.0", + "mdast-util-gfm-footnote": "^1.0.0", + "mdast-util-gfm-strikethrough": "^1.0.0", + "mdast-util-gfm-table": "^1.0.0", + "mdast-util-gfm-task-list-item": "^1.0.0", + "mdast-util-to-markdown": "^1.0.0" + } + }, + "mdast-util-gfm-autolink-literal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz", + "integrity": "sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==", + "requires": { + "@types/mdast": "^3.0.0", + "ccount": "^2.0.0", + "mdast-util-find-and-replace": "^2.0.0", + "micromark-util-character": "^1.0.0" + } + }, + "mdast-util-gfm-footnote": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz", + "integrity": "sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==", + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0", + "micromark-util-normalize-identifier": "^1.0.0" + } + }, + "mdast-util-gfm-strikethrough": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz", + "integrity": "sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==", + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" + } + }, + "mdast-util-gfm-table": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz", + "integrity": "sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==", + "requires": { + "@types/mdast": "^3.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-to-markdown": "^1.3.0" + } + }, + "mdast-util-gfm-task-list-item": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz", + "integrity": "sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==", + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" + } + }, + "mdast-util-phrasing": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-3.0.1.tgz", + "integrity": "sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg==", + "requires": { + "@types/mdast": "^3.0.0", + "unist-util-is": "^5.0.0" + } + }, + "mdast-util-to-markdown": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz", + "integrity": "sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==", + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^3.0.0", + "mdast-util-to-string": "^3.0.0", + "micromark-util-decode-string": "^1.0.0", + "unist-util-visit": "^4.0.0", + "zwitch": "^2.0.0" + } + }, + "mdast-util-to-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", + "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", + "requires": { + "@types/mdast": "^3.0.0" + } + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "requires": { + "fs-monkey": "^1.0.4" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "micromark": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", + "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", + "requires": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "micromark-core-commonmark": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", + "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", + "requires": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "micromark-extension-gfm": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.3.tgz", + "integrity": "sha512-vb9OoHqrhCmbRidQv/2+Bc6pkP0FrtlhurxZofvOEy5o8RtuuvTq+RQ1Vw5ZDNrVraQZu3HixESqbG+0iKk/MQ==", + "requires": { + "micromark-extension-gfm-autolink-literal": "^1.0.0", + "micromark-extension-gfm-footnote": "^1.0.0", + "micromark-extension-gfm-strikethrough": "^1.0.0", + "micromark-extension-gfm-table": "^1.0.0", + "micromark-extension-gfm-tagfilter": "^1.0.0", + "micromark-extension-gfm-task-list-item": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-extension-gfm-autolink-literal": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.5.tgz", + "integrity": "sha512-z3wJSLrDf8kRDOh2qBtoTRD53vJ+CWIyo7uyZuxf/JAbNJjiHsOpG1y5wxk8drtv3ETAHutCu6N3thkOOgueWg==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-extension-gfm-footnote": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.1.2.tgz", + "integrity": "sha512-Yxn7z7SxgyGWRNa4wzf8AhYYWNrwl5q1Z8ii+CSTTIqVkmGZF1CElX2JI8g5yGoM3GAman9/PVCUFUSJ0kB/8Q==", + "requires": { + "micromark-core-commonmark": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-extension-gfm-strikethrough": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.7.tgz", + "integrity": "sha512-sX0FawVE1o3abGk3vRjOH50L5TTLr3b5XMqnP9YDRb34M0v5OoZhG+OHFz1OffZ9dlwgpTBKaT4XW/AsUVnSDw==", + "requires": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-extension-gfm-table": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.7.tgz", + "integrity": "sha512-3ZORTHtcSnMQEKtAOsBQ9/oHp9096pI/UvdPtN7ehKvrmZZ2+bbWhi0ln+I9drmwXMt5boocn6OlwQzNXeVeqw==", + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-extension-gfm-tagfilter": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.2.tgz", + "integrity": "sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g==", + "requires": { + "micromark-util-types": "^1.0.0" + } + }, + "micromark-extension-gfm-task-list-item": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.5.tgz", + "integrity": "sha512-RMFXl2uQ0pNQy6Lun2YBYT9g9INXtWJULgbt01D/x8/6yJ2qpKyzdZD3pi6UIkzF++Da49xAelVKUeUMqd5eIQ==", + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-factory-destination": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", + "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-factory-label": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", + "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-factory-title": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", + "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-factory-whitespace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", + "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "requires": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-chunked": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", + "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-classify-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", + "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-combine-extensions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", + "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", + "requires": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-decode-numeric-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz", + "integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==", + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-decode-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz", + "integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==", + "requires": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", + "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==" + }, + "micromark-util-html-tag-name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", + "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==" + }, + "micromark-util-normalize-identifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", + "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-resolve-all": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", + "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", + "requires": { + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-sanitize-uri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", + "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-subtokenize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", + "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", + "requires": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==" + }, + "micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" + }, + "mini-css-extract-plugin": { + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", + "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", + "requires": { + "schema-utils": "^4.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "optional": true + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "optional": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + } + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, + "moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + }, + "mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "nan": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", + "optional": true + }, + "nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==" + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "optional": true, + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "optional": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "optional": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "optional": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + }, + "node-releases": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "optional": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "optional": true, + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "requires": { + "boolbase": "^1.0.0" + } + }, + "nwsapi": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.5.tgz", + "integrity": "sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==" + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.6.tgz", + "integrity": "sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==", + "requires": { + "array.prototype.reduce": "^1.0.5", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.21.2", + "safe-array-concat": "^1.0.0" + } + }, + "object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "requires": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "path2d-polyfill": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", + "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==" + }, + "pdfjs-dist": { + "version": "3.4.120", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.4.120.tgz", + "integrity": "sha512-B1hw9ilLG4m/jNeFA0C2A0PZydjxslP8ylU+I4XM7Bzh/xWETo9EiBV848lh0O0hLut7T6lK1V7cpAXv5BhxWw==", + "requires": { + "canvas": "^2.11.0", + "path2d-polyfill": "^2.0.1", + "web-streams-polyfill": "^3.2.1" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" + }, + "pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==" + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + } + } + }, + "pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" + } + } + }, + "postcss": { + "version": "8.4.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", + "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "requires": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-browser-comments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", + "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", + "requires": {} + }, + "postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "requires": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-properties": { + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "requires": {} + }, + "postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "requires": {} + }, + "postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "requires": {} + }, + "postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "requires": {} + }, + "postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-flexbugs-fixes": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", + "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", + "requires": {} + }, + "postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "requires": {} + }, + "postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "requires": {} + }, + "postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "requires": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "requires": {} + }, + "postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "requires": { + "camelcase-css": "^2.0.1" + } + }, + "postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-load-config": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", + "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "requires": { + "lilconfig": "^2.0.5", + "yaml": "^2.1.1" + }, + "dependencies": { + "yaml": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", + "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==" + } + } + }, + "postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "requires": {} + }, + "postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "requires": {} + }, + "postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "requires": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + } + }, + "postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "requires": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "requires": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "requires": {} + }, + "postcss-modules-local-by-default": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "requires": { + "postcss-selector-parser": "^6.0.11" + } + }, + "postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "requires": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-normalize": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-10.0.1.tgz", + "integrity": "sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA==", + "requires": { + "@csstools/normalize.css": "*", + "postcss-browser-comments": "^4", + "sanitize.css": "*" + } + }, + "postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "requires": {} + }, + "postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "requires": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-opacity-percentage": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", + "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", + "requires": {} + }, + "postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "requires": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "requires": {} + }, + "postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-preset-env": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.3.tgz", + "integrity": "sha512-T1LgRm5uEVFSEF83vHZJV2z19lHg4yJuZ6gXZZkqVsqv63nlr6zabMH3l4Pc01FQCyfWVrh2GaUeCVy9Po+Aag==", + "requires": { + "@csstools/postcss-cascade-layers": "^1.1.1", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.1.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.10", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.2.0", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "requires": {} + }, + "postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "requires": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + }, + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "requires": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + } + } + } + }, + "postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "prettier-quick": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/prettier-quick/-/prettier-quick-0.0.5.tgz", + "integrity": "sha512-5zOMSPAK7JQMNWjtxAy35XPgRN8TQY+khgpNhznQ30Zsv6V0hOIjre8X5cTrtdqa3NKZWWF1+TNS5+1LX/3a0w==", + "dev": true + }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==" + }, + "pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "requires": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + } + } + }, + "prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "requires": { + "asap": "~2.0.6" + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + } + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==" + }, + "qrcode.react": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-3.1.0.tgz", + "integrity": "sha512-oyF+Urr3oAMUG/OiOuONL3HXM+53wvuH3mtIWQrYmsXoAq0DkvZp2RYUWFSMFtbdOpuS++9v+WAkzNVkMlNW6Q==", + "requires": {} + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "requires": { + "performance-now": "^2.1.0" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "rc-align": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-4.0.15.tgz", + "integrity": "sha512-wqJtVH60pka/nOX7/IspElA8gjPNQKIx/ZqJ6heATCkXpe1Zg4cPVrMD2vC96wjsFFL8WsmhPbx9tdMo1qqlIA==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "dom-align": "^1.7.0", + "rc-util": "^5.26.0", + "resize-observer-polyfill": "^1.5.1" + } + }, + "rc-cascader": { + "version": "3.21.2", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.21.2.tgz", + "integrity": "sha512-J7GozpgsLaOtzfIHFJFuh4oFY0ePb1w10twqK6is3pAkqHkca/PsokbDr822KIRZ8/CK8CqevxohuPDVZ1RO/A==", + "requires": { + "@babel/runtime": "^7.12.5", + "array-tree-filter": "^2.1.0", + "classnames": "^2.3.1", + "rc-select": "~14.11.0", + "rc-tree": "~5.8.1", + "rc-util": "^5.37.0" + } + }, + "rc-checkbox": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.1.0.tgz", + "integrity": "sha512-PAwpJFnBa3Ei+5pyqMMXdcKYKNBMS+TvSDiLdDnARnMJHC8ESxwPfm4Ao1gJiKtWLdmGfigascnCpwrHFgoOBQ==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.25.2" + } + }, + "rc-collapse": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.7.2.tgz", + "integrity": "sha512-ZRw6ipDyOnfLFySxAiCMdbHtb5ePAsB9mT17PA6y1mRD/W6KHRaZeb5qK/X9xDV1CqgyxMpzw0VdS74PCcUk4A==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.3.4", + "rc-util": "^5.27.0" + } + }, + "rc-dialog": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.3.4.tgz", + "integrity": "sha512-975X3018GhR+EjZFbxA2Z57SX5rnu0G0/OxFgMMvZK4/hQWEm3MHaNvP4wXpxYDoJsp+xUvVW+GB9CMMCm81jA==", + "requires": { + "@babel/runtime": "^7.10.1", + "@rc-component/portal": "^1.0.0-8", + "classnames": "^2.2.6", + "rc-motion": "^2.3.0", + "rc-util": "^5.21.0" + } + }, + "rc-drawer": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.0.0.tgz", + "integrity": "sha512-ePcS4KtQnn57bCbVXazHN2iC8nTPCXlWEIA/Pft87Pd9U7ZeDkdRzG47jWG2/TAFXFlFltRAMcslqmUM8NPCGA==", + "requires": { + "@babel/runtime": "^7.10.1", + "@rc-component/portal": "^1.1.1", + "classnames": "^2.2.6", + "rc-motion": "^2.6.1", + "rc-util": "^5.36.0" + } + }, + "rc-dropdown": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.1.0.tgz", + "integrity": "sha512-VZjMunpBdlVzYpEdJSaV7WM7O0jf8uyDjirxXLZRNZ+tAC+NzD3PXPEtliFwGzVwBBdCmGuSqiS9DWcOLxQ9tw==", + "requires": { + "@babel/runtime": "^7.18.3", + "@rc-component/trigger": "^1.7.0", + "classnames": "^2.2.6", + "rc-util": "^5.17.0" + } + }, + "rc-field-form": { + "version": "1.41.0", + "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.41.0.tgz", + "integrity": "sha512-k9AS0wmxfJfusWDP/YXWTpteDNaQ4isJx9UKxx4/e8Dub4spFeZ54/EuN2sYrMRID/+hUznPgVZeg+Gf7XSYCw==", + "requires": { + "@babel/runtime": "^7.18.0", + "async-validator": "^4.1.0", + "rc-util": "^5.32.2" + } + }, + "rc-image": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.5.1.tgz", + "integrity": "sha512-Z9loECh92SQp0nSipc0MBuf5+yVC05H/pzC+Nf8xw1BKDFUJzUeehYBjaWlxly8VGBZJcTHYri61Fz9ng1G3Ag==", + "requires": { + "@babel/runtime": "^7.11.2", + "@rc-component/portal": "^1.0.2", + "classnames": "^2.2.6", + "rc-dialog": "~9.3.4", + "rc-motion": "^2.6.2", + "rc-util": "^5.34.1" + } + }, + "rc-input": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.4.3.tgz", + "integrity": "sha512-aHyQUAIRmTlOnvk5EcNqEpJ+XMtfMpYRAJayIlJfsvvH9cAKUWboh4egm23vgMA7E+c/qm4BZcnrDcA960GC1w==", + "requires": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.18.1" + } + }, + "rc-input-number": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-8.6.1.tgz", + "integrity": "sha512-gaAMUKtUKLktJ3Yx93tjgYY1M0HunnoqzPEqkb9//Ydup4DcG0TFL9yHBA3pgVdNIt5f0UWyHCgFBj//JxeD6A==", + "requires": { + "@babel/runtime": "^7.10.1", + "@rc-component/mini-decimal": "^1.0.1", + "classnames": "^2.2.5", + "rc-input": "~1.4.0", + "rc-util": "^5.28.0" + } + }, + "rc-mentions": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.10.1.tgz", + "integrity": "sha512-72qsEcr/7su+a07ndJ1j8rI9n0Ka/ngWOLYnWMMv0p2mi/5zPwPrEDTt6Uqpe8FWjWhueDJx/vzunL6IdKDYMg==", + "requires": { + "@babel/runtime": "^7.22.5", + "@rc-component/trigger": "^1.5.0", + "classnames": "^2.2.6", + "rc-input": "~1.4.0", + "rc-menu": "~9.12.0", + "rc-textarea": "~1.6.1", + "rc-util": "^5.34.1" + } + }, + "rc-menu": { + "version": "9.12.4", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.12.4.tgz", + "integrity": "sha512-t2NcvPLV1mFJzw4F21ojOoRVofK2rWhpKPx69q2raUsiHPDP6DDevsBILEYdsIegqBeSXoWs2bf6CueBKg3BFg==", + "requires": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^1.17.0", + "classnames": "2.x", + "rc-motion": "^2.4.3", + "rc-overflow": "^1.3.1", + "rc-util": "^5.27.0" + } + }, + "rc-motion": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.9.0.tgz", + "integrity": "sha512-XIU2+xLkdIr1/h6ohPZXyPBMvOmuyFZQ/T0xnawz+Rh+gh4FINcnZmMT5UTIj6hgI0VLDjTaPeRd+smJeSPqiQ==", + "requires": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.21.0" + } + }, + "rc-notification": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.3.0.tgz", + "integrity": "sha512-WCf0uCOkZ3HGfF0p1H4Sgt7aWfipxORWTPp7o6prA3vxwtWhtug3GfpYls1pnBp4WA+j8vGIi5c2/hQRpGzPcQ==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.9.0", + "rc-util": "^5.20.1" + } + }, + "rc-overflow": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.3.2.tgz", + "integrity": "sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==", + "requires": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.37.0" + } + }, + "rc-pagination": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-4.0.4.tgz", + "integrity": "sha512-GGrLT4NgG6wgJpT/hHIpL9nELv27A1XbSZzECIuQBQTVSf4xGKxWr6I/jhpRPauYEWEbWVw22ObG6tJQqwJqWQ==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.38.0" + } + }, + "rc-picker": { + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.7.6.tgz", + "integrity": "sha512-H9if/BUJUZBOhPfWcPeT15JUI3/ntrG9muzERrXDkSoWmDj4yzmBvumozpxYrHwjcKnjyDGAke68d+whWwvhHA==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "date-fns": "2.x", + "dayjs": "1.x", + "moment": "^2.24.0", + "rc-trigger": "^5.0.4", + "rc-util": "^5.37.0", + "shallowequal": "^1.1.0" + } + }, + "rc-progress": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-3.5.1.tgz", + "integrity": "sha512-V6Amx6SbLRwPin/oD+k1vbPrO8+9Qf8zW1T8A7o83HdNafEVvAxPV5YsgtKFP+Ud5HghLj33zKOcEHrcrUGkfw==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-util": "^5.16.1" + } + }, + "rc-rate": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.12.0.tgz", + "integrity": "sha512-g092v5iZCdVzbjdn28FzvWebK2IutoVoiTeqoLTj9WM7SjA/gOJIw5/JFZMRyJYYVe1jLAU2UhAfstIpCNRozg==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.0.1" + } + }, + "rc-resize-observer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.0.tgz", + "integrity": "sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q==", + "requires": { + "@babel/runtime": "^7.20.7", + "classnames": "^2.2.1", + "rc-util": "^5.38.0", + "resize-observer-polyfill": "^1.5.1" + } + }, + "rc-segmented": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.2.2.tgz", + "integrity": "sha512-Mq52M96QdHMsNdE/042ibT5vkcGcD5jxKp7HgPC2SRofpia99P5fkfHy1pEaajLMF/kj0+2Lkq1UZRvqzo9mSA==", + "requires": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-motion": "^2.4.4", + "rc-util": "^5.17.0" + } + }, + "rc-select": { + "version": "14.11.0", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.11.0.tgz", + "integrity": "sha512-8J8G/7duaGjFiTXCBLWfh5P+KDWyA3KTlZDfV3xj/asMPqB2cmxfM+lH50wRiPIRsCQ6EbkCFBccPuaje3DHIg==", + "requires": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^1.5.0", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-overflow": "^1.3.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.2" + } + }, + "rc-slider": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-10.5.0.tgz", + "integrity": "sha512-xiYght50cvoODZYI43v3Ylsqiw14+D7ELsgzR40boDZaya1HFa1Etnv9MDkQE8X/UrXAffwv2AcNAhslgYuDTw==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.27.0" + } + }, + "rc-steps": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-6.0.1.tgz", + "integrity": "sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==", + "requires": { + "@babel/runtime": "^7.16.7", + "classnames": "^2.2.3", + "rc-util": "^5.16.1" + } + }, + "rc-switch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz", + "integrity": "sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==", + "requires": { + "@babel/runtime": "^7.21.0", + "classnames": "^2.2.1", + "rc-util": "^5.30.0" + } + }, + "rc-table": { + "version": "7.37.0", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.37.0.tgz", + "integrity": "sha512-hEB17ktLRVfVmdo+U8MjGr+PuIgdQ8Cxj/N5lwMvP/Az7TOrQxwTMLVEDoj207tyPYLTWifHIF9EJREWwyk67g==", + "requires": { + "@babel/runtime": "^7.10.1", + "@rc-component/context": "^1.4.0", + "classnames": "^2.2.5", + "rc-resize-observer": "^1.1.0", + "rc-util": "^5.37.0", + "rc-virtual-list": "^3.11.1" + } + }, + "rc-tabs": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-14.0.0.tgz", + "integrity": "sha512-lp1YWkaPnjlyhOZCPrAWxK6/P6nMGX/BAZcAC3nuVwKz0Byfp+vNnQKK8BRCP2g/fzu+SeB5dm9aUigRu3tRkQ==", + "requires": { + "@babel/runtime": "^7.11.2", + "classnames": "2.x", + "rc-dropdown": "~4.1.0", + "rc-menu": "~9.12.0", + "rc-motion": "^2.6.2", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.34.1" + } + }, + "rc-textarea": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.6.3.tgz", + "integrity": "sha512-8k7+8Y2GJ/cQLiClFMg8kUXOOdvcFQrnGeSchOvI2ZMIVvX5a3zQpLxoODL0HTrvU63fPkRmMuqaEcOF9dQemA==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-input": "~1.4.0", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.27.0" + } + }, + "rc-tooltip": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.1.3.tgz", + "integrity": "sha512-HMSbSs5oieZ7XddtINUddBLSVgsnlaSb3bZrzzGWjXa7/B7nNedmsuz72s7EWFEro9mNa7RyF3gOXKYqvJiTcQ==", + "requires": { + "@babel/runtime": "^7.11.2", + "@rc-component/trigger": "^1.18.0", + "classnames": "^2.3.1" + } + }, + "rc-tree": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.8.2.tgz", + "integrity": "sha512-xH/fcgLHWTLmrSuNphU8XAqV7CdaOQgm4KywlLGNoTMhDAcNR3GVNP6cZzb0GrKmIZ9yae+QLot/cAgUdPRMzg==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.1" + } + }, + "rc-tree-select": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.17.0.tgz", + "integrity": "sha512-7sRGafswBhf7n6IuHyCEFCildwQIgyKiV8zfYyUoWfZEFdhuk7lCH+DN0aHt+oJrdiY9+6Io/LDXloGe01O8XQ==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-select": "~14.11.0-0", + "rc-tree": "~5.8.1", + "rc-util": "^5.16.1" + } + }, + "rc-trigger": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.3.4.tgz", + "integrity": "sha512-mQv+vas0TwKcjAO2izNPkqR4j86OemLRmvL2nOzdP9OWNWA1ivoTt5hzFqYNW9zACwmTezRiN8bttrC7cZzYSw==", + "requires": { + "@babel/runtime": "^7.18.3", + "classnames": "^2.2.6", + "rc-align": "^4.0.0", + "rc-motion": "^2.0.0", + "rc-util": "^5.19.2" + } + }, + "rc-upload": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.5.2.tgz", + "integrity": "sha512-QO3ne77DwnAPKFn0bA5qJM81QBjQi0e0NHdkvpFyY73Bea2NfITiotqJqVjHgeYPOJu5lLVR32TNGP084aSoXA==", + "requires": { + "@babel/runtime": "^7.18.3", + "classnames": "^2.2.5", + "rc-util": "^5.2.0" + } + }, + "rc-util": { + "version": "5.38.1", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.38.1.tgz", + "integrity": "sha512-e4ZMs7q9XqwTuhIK7zBIVFltUtMSjphuPPQXHoHlzRzNdOwUxDejo0Zls5HYaJfRKNURcsS/ceKVULlhjBrxng==", + "requires": { + "@babel/runtime": "^7.18.3", + "react-is": "^18.2.0" + } + }, + "rc-virtual-list": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.11.3.tgz", + "integrity": "sha512-tu5UtrMk/AXonHwHxUogdXAWynaXsrx1i6dsgg+lOo/KJSF8oBAcprh1z5J3xgnPJD5hXxTL58F8s8onokdt0Q==", + "requires": { + "@babel/runtime": "^7.20.0", + "classnames": "^2.2.6", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.36.0" + } + }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-app-polyfill": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz", + "integrity": "sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==", + "requires": { + "core-js": "^3.19.2", + "object-assign": "^4.1.1", + "promise": "^8.1.0", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.9", + "whatwg-fetch": "^3.6.2" + } + }, + "react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "requires": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==" + } + } + }, + "react-dnd": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", + "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==", + "requires": { + "@react-dnd/invariant": "^4.0.1", + "@react-dnd/shallowequal": "^4.0.1", + "dnd-core": "^16.0.1", + "fast-deep-equal": "^3.1.3", + "hoist-non-react-statics": "^3.3.2" + } + }, + "react-dnd-html5-backend": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz", + "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==", + "requires": { + "dnd-core": "^16.0.1" + } + }, + "react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "react-refresh": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", + "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" + }, + "react-router": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.13.0.tgz", + "integrity": "sha512-Si6KnfEnJw7gUQkNa70dlpI1bul46FuSxX5t5WwlUBxE25DAz2BjVkwaK8Y2s242bQrZPXCpmwLPtIO5pv4tXg==", + "requires": { + "@remix-run/router": "1.6.3" + } + }, + "react-router-dom": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.13.0.tgz", + "integrity": "sha512-6Nqoqd7fgwxxVGdbiMHTpDHCYPq62d7Wk1Of7B82vH7ZPwwsRaIa22zRZKPPg413R5REVNiyuQPKDG1bubcOFA==", + "requires": { + "@remix-run/router": "1.6.3", + "react-router": "6.13.0" + } + }, + "react-scripts": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", + "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", + "requires": { + "@babel/core": "^7.16.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", + "@svgr/webpack": "^5.5.0", + "babel-jest": "^27.4.2", + "babel-loader": "^8.2.3", + "babel-plugin-named-asset-import": "^0.3.8", + "babel-preset-react-app": "^10.0.1", + "bfj": "^7.0.2", + "browserslist": "^4.18.1", + "camelcase": "^6.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "css-loader": "^6.5.1", + "css-minimizer-webpack-plugin": "^3.2.0", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "eslint": "^8.3.0", + "eslint-config-react-app": "^7.0.1", + "eslint-webpack-plugin": "^3.1.1", + "file-loader": "^6.2.0", + "fs-extra": "^10.0.0", + "fsevents": "^2.3.2", + "html-webpack-plugin": "^5.5.0", + "identity-obj-proxy": "^3.0.0", + "jest": "^27.4.3", + "jest-resolve": "^27.4.2", + "jest-watch-typeahead": "^1.0.0", + "mini-css-extract-plugin": "^2.4.5", + "postcss": "^8.4.4", + "postcss-flexbugs-fixes": "^5.0.2", + "postcss-loader": "^6.2.1", + "postcss-normalize": "^10.0.1", + "postcss-preset-env": "^7.0.1", + "prompts": "^2.4.2", + "react-app-polyfill": "^3.0.0", + "react-dev-utils": "^12.0.1", + "react-refresh": "^0.11.0", + "resolve": "^1.20.0", + "resolve-url-loader": "^4.0.0", + "sass-loader": "^12.3.0", + "semver": "^7.3.5", + "source-map-loader": "^3.0.0", + "style-loader": "^3.3.1", + "tailwindcss": "^3.0.2", + "terser-webpack-plugin": "^5.2.5", + "webpack": "^5.64.4", + "webpack-dev-server": "^4.6.0", + "webpack-manifest-plugin": "^4.0.2", + "workbox-webpack-plugin": "^6.4.1" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "react-social-login-buttons": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/react-social-login-buttons/-/react-social-login-buttons-3.9.1.tgz", + "integrity": "sha512-KtucVWvdnIZ0icG99WJ3usQUJYmlKsOIBYGyngcuNSVyyYdZtif4KHY80qnCg+teDlgYr54ToQtg3x26ZqaS2w==", + "requires": {} + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "requires": { + "pify": "^2.3.0" + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "requires": { + "minimatch": "^3.0.5" + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "regenerator-transform": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" + }, + "regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + } + }, + "regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "requires": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==" + }, + "remark-gfm": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", + "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==", + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-gfm": "^2.0.0", + "micromark-extension-gfm": "^2.0.0", + "unified": "^10.0.0" + } + }, + "renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "requires": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "resolve-url-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", + "integrity": "sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==", + "requires": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^7.0.35", + "source-map": "0.6.1" + }, + "dependencies": { + "picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "requires": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==" + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "requires": { + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "requires": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "dependencies": { + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "requires": { + "randombytes": "^2.1.0" + } + } + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "requires": { + "mri": "^1.1.0" + } + }, + "safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sanitize.css": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", + "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" + }, + "sass-loader": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "requires": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "requires": { + "xmlchars": "^2.2.0" + } + }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + } + } + }, + "scroll-into-view-if-needed": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", + "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==", + "requires": { + "compute-scroll-into-view": "^3.0.2" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "requires": { + "node-forge": "^1" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "optional": true + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "optional": true + }, + "simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "requires": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "socket.io-client": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", + "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + } + }, + "socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + } + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "source-map-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", + "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", + "requires": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.1" + } + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" + }, + "stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" + } + } + }, + "stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "requires": { + "internal-slot": "^1.0.4" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-convert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", + "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==" + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + } + } + }, + "string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" + }, + "strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==" + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "requires": { + "min-indent": "^1.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + }, + "style-loader": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", + "integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==", + "requires": {} + }, + "stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "requires": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + } + }, + "stylis": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", + "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==" + }, + "sucrase": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", + "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "dependencies": { + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==" + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + }, + "dependencies": { + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + } + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "requires": { + "boolbase": "~1.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, + "tailwindcss": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", + "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", + "requires": { + "@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.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.18.2", + "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", + "postcss-value-parser": "^4.2.0", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "dependencies": { + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" + }, + "tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "optional": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + } + } + }, + "temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==" + }, + "tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "requires": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "dependencies": { + "type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==" + } + } + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "terser": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.18.0.tgz", + "integrity": "sha512-pdL757Ig5a0I+owA42l6tIuEycRuM7FPY4n62h44mRLRfnOxJkkOHd6i89dOpwZlpF6JXBwaAHF6yWzFrt+QyA==", + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "requires": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "throat": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", + "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==" + }, + "throttle-debounce": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.0.tgz", + "integrity": "sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg==" + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "dependencies": { + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==" + } + } + }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "requires": { + "punycode": "^2.1.1" + } + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + }, + "tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==" + }, + "ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, + "tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "requires": { + "minimist": "^1.2.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==" + } + } + }, + "tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "peer": true + }, + "uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "optional": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==" + }, + "unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" + }, + "unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "requires": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "dependencies": { + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + } + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + } + }, + "unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==" + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" + }, + "update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "requires": {} + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "requires": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "dependencies": { + "kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" + } + } + }, + "v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + } + }, + "validate.io-array": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz", + "integrity": "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==" + }, + "validate.io-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz", + "integrity": "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==" + }, + "validate.io-integer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz", + "integrity": "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==", + "requires": { + "validate.io-number": "^1.0.3" + } + }, + "validate.io-integer-array": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz", + "integrity": "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==", + "requires": { + "validate.io-array": "^1.0.3", + "validate.io-integer": "^1.0.4" + } + }, + "validate.io-number": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz", + "integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "requires": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + } + }, + "vfile-message": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + } + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "requires": { + "makeerror": "1.0.12" + } + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==" + }, + "webpack": { + "version": "5.87.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.87.0.tgz", + "integrity": "sha512-GOu1tNbQ7p1bDEoFRs2YPcfyGs8xq52yyPBZ3m2VGnXGtV9MxjrkABHm4V9Ia280OefsSLzvbVoXcfLxjKY/Iw==", + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + } + } + }, + "webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "dependencies": { + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + }, + "ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "requires": {} + } + } + }, + "webpack-manifest-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", + "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", + "requires": { + "tapable": "^2.0.0", + "webpack-sources": "^2.2.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "webpack-sources": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", + "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", + "requires": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + } + } + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==" + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "requires": { + "iconv-lite": "0.4.24" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" + }, + "workbox-background-sync": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.6.0.tgz", + "integrity": "sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==", + "requires": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "workbox-broadcast-update": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.6.0.tgz", + "integrity": "sha512-nm+v6QmrIFaB/yokJmQ/93qIJ7n72NICxIwQwe5xsZiV2aI93MGGyEyzOzDPVz5THEr5rC3FJSsO3346cId64Q==", + "requires": { + "workbox-core": "6.6.0" + } + }, + "workbox-build": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.6.0.tgz", + "integrity": "sha512-Tjf+gBwOTuGyZwMz2Nk/B13Fuyeo0Q84W++bebbVsfr9iLkDSo6j6PST8tET9HYA58mlRXwlMGpyWO8ETJiXdQ==", + "requires": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.11.1", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^5.2.0", + "@rollup/plugin-node-resolve": "^11.2.1", + "@rollup/plugin-replace": "^2.4.1", + "@surma/rollup-plugin-off-main-thread": "^2.2.3", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "lodash": "^4.17.20", + "pretty-bytes": "^5.3.0", + "rollup": "^2.43.1", + "rollup-plugin-terser": "^7.0.0", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "6.6.0", + "workbox-broadcast-update": "6.6.0", + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-google-analytics": "6.6.0", + "workbox-navigation-preload": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-range-requests": "6.6.0", + "workbox-recipes": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0", + "workbox-streams": "6.6.0", + "workbox-sw": "6.6.0", + "workbox-window": "6.6.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "requires": { + "whatwg-url": "^7.0.0" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "requires": { + "punycode": "^2.1.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, + "workbox-cacheable-response": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.6.0.tgz", + "integrity": "sha512-JfhJUSQDwsF1Xv3EV1vWzSsCOZn4mQ38bWEBR3LdvOxSPgB65gAM6cS2CX8rkkKHRgiLrN7Wxoyu+TuH67kHrw==", + "requires": { + "workbox-core": "6.6.0" + } + }, + "workbox-core": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.6.0.tgz", + "integrity": "sha512-GDtFRF7Yg3DD859PMbPAYPeJyg5gJYXuBQAC+wyrWuuXgpfoOrIQIvFRZnQ7+czTIQjIr1DhLEGFzZanAT/3bQ==" + }, + "workbox-expiration": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.6.0.tgz", + "integrity": "sha512-baplYXcDHbe8vAo7GYvyAmlS4f6998Jff513L4XvlzAOxcl8F620O91guoJ5EOf5qeXG4cGdNZHkkVAPouFCpw==", + "requires": { + "idb": "^7.0.1", + "workbox-core": "6.6.0" + } + }, + "workbox-google-analytics": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.6.0.tgz", + "integrity": "sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==", + "requires": { + "workbox-background-sync": "6.6.0", + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "workbox-navigation-preload": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.6.0.tgz", + "integrity": "sha512-utNEWG+uOfXdaZmvhshrh7KzhDu/1iMHyQOV6Aqup8Mm78D286ugu5k9MFD9SzBT5TcwgwSORVvInaXWbvKz9Q==", + "requires": { + "workbox-core": "6.6.0" + } + }, + "workbox-precaching": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.6.0.tgz", + "integrity": "sha512-eYu/7MqtRZN1IDttl/UQcSZFkHP7dnvr/X3Vn6Iw6OsPMruQHiVjjomDFCNtd8k2RdjLs0xiz9nq+t3YVBcWPw==", + "requires": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "workbox-range-requests": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.6.0.tgz", + "integrity": "sha512-V3aICz5fLGq5DpSYEU8LxeXvsT//mRWzKrfBOIxzIdQnV/Wj7R+LyJVTczi4CQ4NwKhAaBVaSujI1cEjXW+hTw==", + "requires": { + "workbox-core": "6.6.0" + } + }, + "workbox-recipes": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.6.0.tgz", + "integrity": "sha512-TFi3kTgYw73t5tg73yPVqQC8QQjxJSeqjXRO4ouE/CeypmP2O/xqmB/ZFBBQazLTPxILUQ0b8aeh0IuxVn9a6A==", + "requires": { + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" + } + }, + "workbox-routing": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.6.0.tgz", + "integrity": "sha512-x8gdN7VDBiLC03izAZRfU+WKUXJnbqt6PG9Uh0XuPRzJPpZGLKce/FkOX95dWHRpOHWLEq8RXzjW0O+POSkKvw==", + "requires": { + "workbox-core": "6.6.0" + } + }, + "workbox-strategies": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.6.0.tgz", + "integrity": "sha512-eC07XGuINAKUWDnZeIPdRdVja4JQtTuc35TZ8SwMb1ztjp7Ddq2CJ4yqLvWzFWGlYI7CG/YGqaETntTxBGdKgQ==", + "requires": { + "workbox-core": "6.6.0" + } + }, + "workbox-streams": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.6.0.tgz", + "integrity": "sha512-rfMJLVvwuED09CnH1RnIep7L9+mj4ufkTyDPVaXPKlhi9+0czCu+SJggWCIFbPpJaAZmp2iyVGLqS3RUmY3fxg==", + "requires": { + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0" + } + }, + "workbox-sw": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.6.0.tgz", + "integrity": "sha512-R2IkwDokbtHUE4Kus8pKO5+VkPHD2oqTgl+XJwh4zbF1HyjAbgNmK/FneZHVU7p03XUt9ICfuGDYISWG9qV/CQ==" + }, + "workbox-webpack-plugin": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.6.0.tgz", + "integrity": "sha512-xNZIZHalboZU66Wa7x1YkjIqEy1gTR+zPM+kjrYJzqN7iurYZBctBLISyScjhkJKYuRrZUP0iqViZTh8rS0+3A==", + "requires": { + "fast-json-stable-stringify": "^2.1.0", + "pretty-bytes": "^5.4.1", + "upath": "^1.2.0", + "webpack-sources": "^1.4.3", + "workbox-build": "6.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + } + } + }, + "workbox-window": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.6.0.tgz", + "integrity": "sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==", + "requires": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "6.6.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "requires": {} + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + }, + "zustand": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.8.tgz", + "integrity": "sha512-4h28KCkHg5ii/wcFFJ5Fp+k1J3gJoasaIbppdgZFO4BPJnsNxL0mQXBSFgOgAdCdBj35aDTPvdAJReTMntFPGg==", + "requires": { + "use-sync-external-store": "1.2.0" + } + }, + "zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==" + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 000000000..755de543c --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,77 @@ +{ + "name": "frontend", + "version": "0.1.0", + "private": true, + "dependencies": { + "@ant-design/icons": "^5.1.4", + "@react-pdf-viewer/core": "^3.12.0", + "@react-pdf-viewer/default-layout": "^3.12.0", + "@react-pdf-viewer/page-navigation": "^3.12.0", + "@rjsf/antd": "^5.16.1", + "@rjsf/core": "^5.8.1", + "@rjsf/utils": "^5.8.1", + "@rjsf/validator-ajv8": "^5.8.1", + "@testing-library/jest-dom": "^5.16.5", + "@testing-library/react": "^13.4.0", + "@testing-library/user-event": "^13.5.0", + "antd": "^5.5.1", + "axios": "^1.4.0", + "cron-validator": "^1.3.1", + "handlebars": "^4.7.8", + "http-proxy-middleware": "^2.0.6", + "js-yaml": "^4.1.0", + "markdown-to-jsx": "^7.2.1", + "moment": "^2.29.4", + "pdfjs-dist": "^3.4.120", + "prismjs": "^1.29.0", + "react": "^18.2.0", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", + "react-dom": "^18.2.0", + "react-router-dom": "^6.11.2", + "react-scripts": "5.0.1", + "react-social-login-buttons": "^3.9.1", + "remark-gfm": "^3.0.1", + "socket.io-client": "^4.7.2", + "zustand": "^4.3.8" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "eslint": "^8.41.0", + "eslint-config-google": "^0.14.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.32.2", + "prettier": "^2.8.8", + "prettier-quick": "^0.0.5", + "webpack": "^5.84.0" + }, + "engines": { + "node": ">=16.0.0 <20", + "npm": ">=8.19.4" + } +} diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b56ceb9d5d35706f0198a3cf94910847b58be6d3 GIT binary patch literal 6044 zcmV;N7h~v&P) zd306Py~jVlb8kSi(T5+fqY)HZ+AW6>e{c#f#l5_5K&bjB@d-rFptd)EA zzQ6rj$@lKNhu{8fQB@3vV#5mC0fQk7jPMObi4ndbl2k2~ic4RS5~nh$Yn>|f4De## z2;UGns+Y?dBGisrjW||NDW|>lNqOk~U9xS%2;UGXs+LNHDs@0SX+_}_1`b(}t@w@b z4UwUGnM@U-mQ=d2u*V4B5IR-M<;*Na-_7_; z#czaf2$ibka;7MckiF=;8P9+r3#I;}LFrUB!Z(CQ^-?*@C($Pm#?e0b$#leTgl`Ci z>SZzm$x`%!dz?+0;y1!KYI0SDm213~q4J--pYA#g$zeK#lc6~7U_AyBH8%7r0|zMB*1h&9RVb)`hW8AAb6y-Y3=;Xb0H zv*Q_LEs@#lN~7YCp}?qKD(BclO7z_v&me1Y)SNOD2nr_%Dc0M=;{+poLs4RcZ^%Ey z_WVs^gl{NHjPMObi4ne`D6yDQc~jUIG_$|prAJynSL!Oh)&h2-Z zQhA53tuB#~#CRGw#8YiPgD+$uocD zN&HQ+4>r#N2WM@=VDN!VgVZj~TKo%TUn6=$RLCYe^HL^Xeosc?Unu($H=;L0hb+UA z#*AT!uP6gvT4<8;TMmd_!cpzN%O!w?3@b8VpWETlfZpGiHo$C|ndR(xHyQ5D-TA zhN8p>-%yko;Ts}}CW{(2(V2##M7*!>8{r%B5AQv`8sQrPK|QXuOTY)DqAq;1b883$ zbM(*HFa&@Rz9IkcDJo}$tr_FzDPD&G2KGM4%-} zu`j}pa*uB)QdE-)e|N9eyus?)=+ z-QdIhXuu4043R^G*BlFKHyi*A@uLkRd_&~u6kc*Hkd7n$Y9s2xH^ZpnWBpqjc-^J! zD?YVhR&@-)pxJLeu6(pYJDrPUY_|UNCE7c;hN451XC0rn8~dn5Hdb&uB^WPWL|MBv*mO@eCkcK zhdPG5CDR^X;6X*5KP)Pz`QlVBf)oB`AHGR!|7P)qNMjRcj#GiuuHPTwi@vrdbVR+! z_a!dF5P6nYoutl34K4dT{NKUf=zWYY8rcL?4BFoSsWH7RvbnwAgF`pL(+) zK~9d1@beUffoWEK+xi2G97{&Go(%YK;;JvQ&H~o^Zx}exm(`-7KG-mXfu`4Ksd9T& zl{%*jw7Ae$pL%HVE_}D4&T3!AWg~e-N_?_X`bTa$^XR?=?!9LTR!(HvFWjT(>xvc6^%@ z@ArhI?^&q*kH8x61NApX!w@_r!am8$1>Utb@@vPk#cKv5QW=bA0JIYy`i_NLsJ

RWt8oIxDplPyDTa7_9nP*pWv|L#~ef5Sltmj&w< zVC(a+L-^vHz{d;z_4pth>zge@F6bwGfj_R=$Zf9gu`M?|Xf^eKU;+QAI z`gc+a|NG;U^i8MgGPiXI%Fly$3=mz}{cA$_3-9_Ect0nNXUE<&a75Tn7}7vFzV}N} z7TqwO8rS+FKLthw?N(P~4c))>I*1~UiF_i1#e}e3Fr>u};R}3#aGu+dLaALp2GMWl z$gkBpZRn0goF3te-IOB-vSobO4j7VCy;62lI0`_7t)0T@RpZq$2vX|Xc1P?vJ*_6Fg2o)(Yyn;HUT8)JaDf})&v!#H)$ngGzD_YlY-6F00U zcY3wsw%ZdPW5s*9OZ2`a*_LFc0(Dq{e<@mnlq%+uI>A1 zXW=iYX$GFj$fzcbt=N>2t<(%a@I9-R!8@Hcr5iVKs$0~htR#+f&Ib<6t!J`Q&l&!= zzEArnY!azObzJ&(b1HmLE(Y%R-LAnCH%!pvyZ>ujYCulTkvl!8eW%mo{!2-^tsZF0 zz_h#Yl}|FTlP+Ioi5wk(T|+=fZOe72EcQxOWS}gBh3~Np-dJ zTCA`p13T%Xfu)@=_>9!H%s}MEP#RZiv;xQYAZNi^{1R}^b<&>!yxO*>OT!l9K>!LvPR~& zjzg)#$Lo7C^xzh~V7TiXGs$+b{5b74ESJN@%G+t%$Q0!YR?04c**9d3)U{2@t4}4^QI=MJN`-U`;+O}&!Y6$z59h+Ht3ZJE_mfA@> zb`7alcn(8cPDlwarEJ3+Kcqo|%erMqiZn4$>RM+bdQ;fG0F64mY)Lv5QwzWGj@J?D zQq&s4saLp#nEo*xN3urPi#W3aZNuP*%xm43^{u~!ATDpn5M>KiENva6_qC+fb)>pL zqOk++|z;f4Th_VICKF=*Q!Hx8V|7=wU%4OivfN~U5 zzvCR6FD%c*sjRWNpL$7lKERMAGPkXqcKr)*M%cdWjDAPY9G>w;X=Y1Li)#La>Mbs% zakj}=msXZ#=2q4mz+i63QCmfU)Hjcm+O|1Zx(H#vu>I*nolYP2P&RMOe9d+9@E?IX zPgvD*&V(>Q-v_*9Wlo=2EEebah9PYPL~2`R&=FgO=(oc5$AP!mYG0b|n==>wvsE3$ zQrG%CBEKP;H&3=<*^`q6p`{|bUA6@^ z@1k7pP;xNkS03v49vjzF_r4?i8|~biv-S!Esc+j)=C$4n`YI6BZ_Rc@E3z5a_a^)8 z!CE<^;W;SOJpR7Mx2zlg~=cDhc;I@hu8L|u#0;8+$Md(*+A z#eQf-?xRHJwVWokt;>+u-w-PEM)dF?)5~W1Y0#e#(gii|g7r;y#NO)+rcQMmC*J2v zo0)MupE8GP2{&Xm1Y~a85mMKB8>Ouuq4EU6IKnvtn=KC#A9``$OlV&5KGf;Wsg);T zvk2G)p`3*^jSfu;jr;|ddy)c0xP^&&ZPF^W>%Imugdy9X((=87J46#8QoH_Wuun%g z1M>NvV7ZHFWwZPiJ@_qrfbyB+v1B3W3L5U3cPAmICVAg#XKEUM4 z$q4fi>kBNrv;PUKSEPisyhBdYMDIX>%bBD}kEhAJ)~iu&qGxHZ1>rfA7f}0Ew#Q%7 z^Y#cj>a@RKAk;P=jAb2*ax7{ci|A2Ac?mKz+CgUOw6Z|=VS*7pz?90bf=r;{=ihTI zUm}$`yZfj=3S7h_ot> zNkn&`C|6RhNk4p2yWv2j^9j0c`pAGbU>!mWN(;gkY;DJq-Wj9^0K1|Hi4WIMU>M4< zJX&$_i#O@CPjgD}8U(=#KNX8*2EuQ`a{z#wnWX=ltb#oB{x0k?BolIehCQWaiSXpVi7}47(+=*sTY(=G-lCqy=dR)*?q9Oc549{CY6mB*ACoq*s z`a-ITGJnHC*c}gmd^HDt_VzEmz$%YUV(GWhsVwr{DczZ<%Y$vhNbyqr-rLJu< z=xxC0VBN}F-a+}kP9ItywjH83)G z*YbikRBooM?9O!3`sI@72p^zH_QB>aK$LDaT#Irc<(gJ%I+?w$ltI?jz*Q9Q_`e0= zF6>y1PTxI~Yo&5Vw1f{~$MLwKD0i`y?^B^^tu@Qs)*%SzBV0*1p&4QD3CcZ`$Q@cy zwjpe1k`X=O12oDbz}aED;lPI|ms75b(tU%hB+kdJry*1V#|P+JcnHs<`fK9D>a+sK z>pr7KG=;xhcBP#c343G94drp-T-}v6C2gd3-7z2+CGP4K=X=BQ25knJgQX9IwHEJ% zXbK;oK@KLyOF&dFd20tAq>~?|TKDgZ)Dxql^+bd-QBEV8DLkB53oJrpA+fTj@}+lo zBD%r{SS*tf77*=_+l>gf66X%aY4VKH4#<6!P}({c^hA)a0ml&LjUqeK0leOIE@2^W z5B+0Q&m?3@w1p3_M81QPQ6}7wSc`BYpE5gD*h4a8_PSCA$HrjmSl|l?hm*Uk#OqN0 z4E!GS_mtRw$YtPIE{VSI0UG62;Oem5NRt+X`w)J~Df*Eg2Bm)Uo^*V61aKHwqd`X@ zj072ht)nssVg3}6HK3oM{0sO1ldGtQL!5Pr2- z9K*v1)5CTp1KJUuz~<+a>x)4)B=ya^!N38utJ{32jm~Y`Q{4pUnI<_Fn@ZptDCbbF z3j%G=1Nk9*fO?5Bn1_LBVY`ws!b{l91sJV%U|I7Pz=>}rrwERI6>FJKIb9p@oQ-mwLk#w5*kmb|RVPvHYy ziK(iAACO;}!P2FJL>7ltz?&#<0B;iGADp7i$={kL4Kf0Y1F<*&HEgBX)C4c&+W`7eBcMmY{;0m5EkyHZ4~pq(=~Rdb$H%MS`8iRvVM0p(cW z^{`zj0&J8U*~0jI6+IM6kKfHJQo zMuqK40r4zx&MuS-HVU&>EY}rS9F4L#Y*z|^jR=?XGA9*^=%G-1{N5x&o9~9mT~3@2 zG@|@B<@#aRj`&UC3m+02GI6d)nMrQ%-^y3k0JE5+kx2*QH^m|RZW`rqgu5e_!X!$3 z3fxX7w=zYuzC1Y}C@$f5(glHNe51I9-%a8h;JYM3Yzr~&r!VV)`-yXVvGnkLF~aXnBD2Fqzy%~?SqhC; zfcq$6ZZ-$w3kf59Cz@m+%IVl#i11aSo#i1F9|QAI9-&-c4cnQhV1%EF1u~3*Oh!2s z7)O5GhVmiM1kC4Uo})?&A|;5Q7~yBaVi}Au0p-N5LmEdAjcwhm0000 + + + + + + + + + Unstract + + + +

+ + diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json new file mode 100644 index 000000000..30caf6595 --- /dev/null +++ b/frontend/public/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "unstract", + "name": "Unstract", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/frontend/sample.env b/frontend/sample.env new file mode 100644 index 000000000..7e9078ed2 --- /dev/null +++ b/frontend/sample.env @@ -0,0 +1 @@ +REACT_APP_BACKEND_URL=http://localhost:8000 diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx new file mode 100644 index 000000000..63e522f29 --- /dev/null +++ b/frontend/src/App.jsx @@ -0,0 +1,42 @@ +import { ConfigProvider, message, theme } from "antd"; +import { BrowserRouter } from "react-router-dom"; + +import { THEME } from "./helpers/GetStaticData.js"; +import { Router } from "./routes/Router.jsx"; +import { useAlertStore } from "./store/alert-store.js"; +import { useSessionStore } from "./store/session-store.js"; + +function App() { + const [messageApi, contextHolder] = message.useMessage(); + const { defaultAlgorithm, darkAlgorithm } = theme; + const { sessionDetails } = useSessionStore(); + const { AlertDetails } = useAlertStore(); + + AlertDetails.content && messageApi.open(AlertDetails); + + return ( + + + {contextHolder} + + + + ); +} + +export { App }; diff --git a/frontend/src/assets/BingAds.svg b/frontend/src/assets/BingAds.svg new file mode 100644 index 000000000..37f4d4cb7 --- /dev/null +++ b/frontend/src/assets/BingAds.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/Unstract.svg b/frontend/src/assets/Unstract.svg new file mode 100644 index 000000000..62883988b --- /dev/null +++ b/frontend/src/assets/Unstract.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/UnstractLogoBlack.svg b/frontend/src/assets/UnstractLogoBlack.svg new file mode 100644 index 000000000..25d9e9e42 --- /dev/null +++ b/frontend/src/assets/UnstractLogoBlack.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/Workflows.svg b/frontend/src/assets/Workflows.svg new file mode 100644 index 000000000..20e711a37 --- /dev/null +++ b/frontend/src/assets/Workflows.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/api-deployments.svg b/frontend/src/assets/api-deployments.svg new file mode 100644 index 000000000..f0a5d2473 --- /dev/null +++ b/frontend/src/assets/api-deployments.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/appdev.svg b/frontend/src/assets/appdev.svg new file mode 100644 index 000000000..699016a69 --- /dev/null +++ b/frontend/src/assets/appdev.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/assertion.svg b/frontend/src/assets/assertion.svg new file mode 100644 index 000000000..5eb46baa0 --- /dev/null +++ b/frontend/src/assets/assertion.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/bg_shape.svg b/frontend/src/assets/bg_shape.svg new file mode 100644 index 000000000..67655d04e --- /dev/null +++ b/frontend/src/assets/bg_shape.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/combined-output.svg b/frontend/src/assets/combined-output.svg new file mode 100644 index 000000000..78a39eae8 --- /dev/null +++ b/frontend/src/assets/combined-output.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/connect_embedding.svg b/frontend/src/assets/connect_embedding.svg new file mode 100644 index 000000000..88a932b17 --- /dev/null +++ b/frontend/src/assets/connect_embedding.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/connect_llm.svg b/frontend/src/assets/connect_llm.svg new file mode 100644 index 000000000..b8f56d062 --- /dev/null +++ b/frontend/src/assets/connect_llm.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/connect_vector_db.svg b/frontend/src/assets/connect_vector_db.svg new file mode 100644 index 000000000..09b098da8 --- /dev/null +++ b/frontend/src/assets/connect_vector_db.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/custom-tools-icon.svg b/frontend/src/assets/custom-tools-icon.svg new file mode 100644 index 000000000..43436e58b --- /dev/null +++ b/frontend/src/assets/custom-tools-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/document.svg b/frontend/src/assets/document.svg new file mode 100644 index 000000000..226bd1b1a --- /dev/null +++ b/frontend/src/assets/document.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/embedding.svg b/frontend/src/assets/embedding.svg new file mode 100644 index 000000000..6081e070f --- /dev/null +++ b/frontend/src/assets/embedding.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/empty.svg b/frontend/src/assets/empty.svg new file mode 100644 index 000000000..54454407d --- /dev/null +++ b/frontend/src/assets/empty.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/etl.svg b/frontend/src/assets/etl.svg new file mode 100644 index 000000000..f776e2916 --- /dev/null +++ b/frontend/src/assets/etl.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/folder.svg b/frontend/src/assets/folder.svg new file mode 100644 index 000000000..10264af84 --- /dev/null +++ b/frontend/src/assets/folder.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/index.js b/frontend/src/assets/index.js new file mode 100644 index 000000000..f1279797c --- /dev/null +++ b/frontend/src/assets/index.js @@ -0,0 +1,43 @@ +import { ReactComponent as SunIcon } from "./sun-icon.svg"; +import { ReactComponent as MoonIcon } from "./moon-icon.svg"; +import { ReactComponent as Logo64 } from "./logo-64.svg"; +import { ReactComponent as Logo24 } from "./logo-24.svg"; +import { ReactComponent as Document } from "./document.svg"; +import { ReactComponent as Folder } from "./folder.svg"; +import { ReactComponent as BingAds } from "./BingAds.svg"; +import { ReactComponent as ToolIcon } from "./tool.svg"; +import { ReactComponent as InputPlaceholder } from "./input-placeholder.svg"; +import { ReactComponent as OutputPlaceholder } from "./output-placeholder.svg"; +import { ReactComponent as ToolIdeInputDocPlaceholder } from "./tool-ide-input-document-placeholder.svg"; +import { ReactComponent as ToolIdePromptsPlaceholder } from "./tool-ide-prompts-placeholder.svg"; +import { ReactComponent as UnstractLogo } from "./Unstract.svg"; +import { ReactComponent as ListOfWfStepsPlaceholder } from "./list-of-wf-steps-placeholder.svg"; +import { ReactComponent as ListOfToolsPlaceholder } from "./list-of-tools-placeholder.svg"; +import { ReactComponent as ApiDeployments } from "./api-deployments.svg"; +import { ReactComponent as StepIcon } from "./steps.svg"; +import { ReactComponent as AssertionIcon } from "./assertion.svg"; +import { ReactComponent as CombinedOutputIcon } from "./combined-output.svg"; +import { ReactComponent as EmptyPlaceholder } from "./empty.svg"; + +export { + SunIcon, + MoonIcon, + Logo64, + Logo24, + Document, + Folder, + BingAds, + ToolIcon, + InputPlaceholder, + OutputPlaceholder, + ToolIdeInputDocPlaceholder, + ToolIdePromptsPlaceholder, + UnstractLogo, + ListOfWfStepsPlaceholder, + ListOfToolsPlaceholder, + ApiDeployments, + StepIcon, + EmptyPlaceholder, + AssertionIcon, + CombinedOutputIcon, +}; diff --git a/frontend/src/assets/input-placeholder.svg b/frontend/src/assets/input-placeholder.svg new file mode 100644 index 000000000..ddce97fe0 --- /dev/null +++ b/frontend/src/assets/input-placeholder.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/landing_bg.png b/frontend/src/assets/landing_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..fdfddb30709850bda38e5ca29d1c16f120ba302d GIT binary patch literal 12629 zcmeHN3sh5Ax~9{P))t1gPDR0n+FqrWC1@3CErg;(3WD(kS|DZ|d{u<_qDUabxhSZJ zSe2qO5`hW|gcKA4gp<_T3g~D+5Jcca1qunmK?s~kNHY86ge1HoH_Tdh?j849>N4lB z$^Kva`~L4gwq~`v*;|%xnV6WEd3^1*&cx*P8tl)TQ@|%)HG2<(f2QsE`kVbGCNt(@ ze_r!g_g~%M!`Jq&b6;+fdvCTF{O64wuHLRDCV2^O4{rIRiOE8Vhnwq$gRgZqxP~-5 zD!lZhfD-a(`W_w}K(M~_kB=m)db{6j@z_v&qb}=0d2pGch(n26N_*i}WV0bZ{Db2I z#6zdvc*o^5>Bd{vTHXZP8(2SF@w!+U+LTfIFlpW9k0q&yylv;DOt84h&4n>joxy^R z^xevMAr{}Q;hjHDNXWY@?~z;Nszu1!muOx#-Q$RgRh0X9SzYJVKAq27Qi@T!y!`(ktKkP&EeaLij)mOCsl#cAo zu**>1w^4LDtMYXN2YKnEs0|sb+e<>$2R&OgpYv{CC92rJq_P?;f2O_v&FB=c;9uy0 z)q_&$c1e>LDWUA)?+lc&(mH0(lKVsNwf@MBn?k>a22h_ zeI8k~ik7aiNw`XRX84vD^HS{+3Tl%A!UXKn^zYRV2O{dTY@p1YmmDL6eGjU6_u+?2 zT$~|t`)e;f&Nwe*`~CquIhxy%R{P0(>Vrq9f-DroiyzO6mYedocb~eUbuZk#<*XE2 zGiucyLs7^+{8>-==Gi^6Z;^TPW&=-?`WebO)-f(S4O&1hhwG?f?~p6|s~MOTI)D{W zTd=d;wT&<{^=q~Bx8P1(+;{Kcnxrznj#arrk#Bny{!jt!esBg}zoar5Y8#MmoFmu?gsS8~jboMM~SErolH@FK~nh~9B+O=4A;l_$7tn|NW zd~q{&E$-+|*sq5#(5XESTfc`sZ+U(dNDE$jWKmXP}m zeH`Dv^y8ni62Uu%$d#d#8q2w@*?w|Zr9N{0=YEFe_$hvqX-M~r@r*uF2dp7wSTBfK$zHpTpVfCig1hL0#;to;H|k6YpUGyMsgtBuWJNr2S}&uccu5@p z2s}cHWU#l_=Y+uIxM%X&Pj4*O!whTF_j@^Ryf;GRv77?t$YwAyU z9XLklF9i;8K?K`6c!Zap+Q18yX|FEF|4)}A=4zKu*V`PR zaIZS_Up`xRl-@2^eqpI8&q?ejuEX!Dkc_mlz}>xkIWgUQ#pk+!8y&_NI=Z+l^=y&+ zAhGc>S6kwkDv#k?YOg<@$QL$L@KazLqca&h=ppOGtJ6zz8)_`&>uv|RIZGKTZ7sV~ z+l_-fZJ}{oU)8**FkHl7RmIMk9j~cKcYMDPcc%Rfe&$@ak&Jjo456dd7uR?;GMuct z?l)+!Hi2rq+SNp}MRXNW;(^Q`eqoZ4=|*2^*hzm*xLq@iQWv}{o-x1GA&oG=XP%rw z$5scjE$AQ)^3->F3hV_XUu}Orv!N8>3)^qLb8_X-d)a@Nem4?vF76A-T>Z)1E@Fy# zm{?bqL`*%HfNi;WX-#Wh?ZD}dE^cC&4l0eV(wXQqXY3mryB@o5lN`?NSXyw4f40YR ztvN&F;{N&&W_EB=`vSkN$+Qgk?glBiq~S2p4(XOR^|1A7I&UQ6JWuDYw>kS>n6)sL zCta$sNg|54s4KT_%UM>Eo=riFicqxS_LsVR7*&9)tL29$ReHPAKMMu-P_kbj)iXT) zN-Q7I;k0^7f;v7mz!gx9?Vr*CIzxEK;(>*SHMoHU{Q03jiB<(=pmBh{P(pA}=>;`h zo$h%I!y**AmBx6tsJ+B)SN!Q7A2vgz zk`6YU`%}ngMZ(8HQ_N>YYE#$DdgZX%$rQ;?m)Rve`)y7Ft3Twgzknqp3JoI%(7*z%1{mIjjGAq=WTLOW0)8!xOQGjGGv# z-F7T{a0}Juc-|ZQgVDMF(=IGN9#20&u_##S@gl31kEH*`>T0@mV9%Kwj49N`2g@I8 zc{@$E&{Hpx~4opeNkU)>ZelY&B4Z{z|*;SOM~{BPl;iK!7kr?s2I&uYVw~3ig`nIID3-w?lNSDN%bX#+aw;V2Qw1 z(%Mn0$r|bE#$OKu%u`&>7smB03^=Ft<(MI23vuX7JsP`j0yOsMfRJOlM2!WlcVe)^4qo|na?p0X%YPEs zmf{Au%GPYji2L&uxWybcvGson+)g@#Cs~Iv(dFM>O!4hxz5#sStqN^oCaPo!s#z*o znM)KM4)%(f7>Q|b4eWna~K%vIV7?1&i&~2F-yR% zG}JzJhFEH7He1EV^Z}!mZ#HIycPMovb>FxEk+V{mqdV!KVAeK_=p9Ryd~|LCg-{>2 zg5c8Gq=g|aEjPQT#v5!&01`A{3ssnfhLj*!TSB30ON`$s4K-kB@epXG^BKwM zMptmWmtORho;h|t&xR(%?1ChWiohgyEF?1Zh#hrci!9Di+X8av<0~t4v`$6ZsgvK1 zd^C>Gc#`Q~p||U3p)sg~ai z8l!4R9aWF@yT=vug#<1us(4I{=FD>1+O6%vI!4Z%tLHkP53C~aoboMVoutaAT3K@Q z+1Mw)xasubQ9Uh)DrP*8N1U;eG#(IvR;4m2UDp7yI6ii>$E}9TG1c33bZ`hB;kr{) z0Lkc{&!&R+K;_68CbP6FN++VT(3-Rqw^Ht?mn@{HnRW+o@`dTyqjYNjFd(zE_04mv zDHiiVk9v^fq3eCw|9R{--?1w+s_Rh$(eV@wSc8X0?`EUTfmPp~zW)j0Ja*DaWBRdW zv{(AWEB)b>{-8IO^Gbifs?CJfe+oszG3tjUxp98!KSufliBK13)kH>tQeY7})Jbj5 z)SCs0jhv~xWLSeikO(UCvaXeyD|k5!X&D#{K0+|8IVnof1^%z37>yM3FO(ks5UMXd zaQY{NQrTCvgpT!ycWfG%8rc6mgT)lbKC#z25{wSke>zf7tF4g_*yzDji_{6k$1-K` zTx)~z!DeIOv12eY`SK(=o$QTaoGx=><59}3TG(z^5;lGMNia?Mk(?MSTWI>(kZ$Za zNbABTM?r&fd#3}1suk=o3RIGzN9+=DVwZ_p;gmmxC8X2iBx8+>`Sjzh*c>RMBSCBxLUyKNtsKn?yXq{{4s!tGm0&6b z(|LzExvsWBB34wl#FPx1!l{uwkAtR1{KA5|N!nQy5 zZO(UyoGSxEDs0{)a!0M{Uvcofy|JJlj2Eg2r{*sr4;87J>JFW6O4)mFUIK%_37_3_ z@FXt6)>Q%eA951zPMCwyU}qPWKOMwMeRgcAE3GrQX9|PmI7p}O{a-Lm47{o^hSNSXr+Bv|T}3fL*IARFAvcEjd-q*3V(>Vcu&-fzgXwL_yl3+kFgu|u;xAfkL9 zU^A?|+bkiu>ajhPv>TF$8QYDfz?%xx(=NIhW%VSFnv{#hH!K?shKYl^Tax|aMQMeV zlmTDb!6Ecap^#~Lno%b(B%wC|lr3f`R*f#Y0Ry5iFls*^>mLo9Wgn;J(u%v3#2n2W zdkRduo`n@c*hdi=RZ-iW*Z^kQGl8sbI3xzYP?_IPt0X#}iVMcx^dPNv%U%AL|NbWl C_haDz literal 0 HcmV?d00001 diff --git a/frontend/src/assets/landing_bg.svg b/frontend/src/assets/landing_bg.svg new file mode 100644 index 000000000..2c7a0d207 --- /dev/null +++ b/frontend/src/assets/landing_bg.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/list-of-tools-placeholder.svg b/frontend/src/assets/list-of-tools-placeholder.svg new file mode 100644 index 000000000..1988926e2 --- /dev/null +++ b/frontend/src/assets/list-of-tools-placeholder.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/list-of-wf-steps-placeholder.svg b/frontend/src/assets/list-of-wf-steps-placeholder.svg new file mode 100644 index 000000000..8a18dda6c --- /dev/null +++ b/frontend/src/assets/list-of-wf-steps-placeholder.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/llm.svg b/frontend/src/assets/llm.svg new file mode 100644 index 000000000..c73174a96 --- /dev/null +++ b/frontend/src/assets/llm.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/login-page-bg.svg b/frontend/src/assets/login-page-bg.svg new file mode 100644 index 000000000..2237f8831 --- /dev/null +++ b/frontend/src/assets/login-page-bg.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/loginPageSS.webp b/frontend/src/assets/loginPageSS.webp new file mode 100644 index 0000000000000000000000000000000000000000..da96ee0621b89a59ff2b9894d4287c0b5a02e0dc GIT binary patch literal 49114 zcmV)3K+C^UNk&G}zW@MNMM6+kP&gpQzW@O6wgR02DgXql0zNSqibNtIp%FS1#2^C% zv$t%E0%t)cFqXrxkFS)zx{9dKLGh3$v>$6^ZQr+2lo@^e~^0c^{?JPT>B;K ztEs%JyyNv>`JdwddB4bf%Kq>Ev-_{(Z_zK!pY?yg`~m)<|E~WD{-gfi_;3IJ|NjvG zi~X(lIsH5RAE*!Jf7?Ie|D65&`BVP`|8M<2xXi2K(&-Y){f3|+#e=zw+@&Dq#xqoHw1{Ac@L@87vz%OBtWcK<8>OZVI657Ym}f202e`#JsR|4-lt@c-rC=KsBZ)Bkb* z`~Lgz|Mb7}JbQlw|0Df(`A^G_urK9**FV^QivL0XL;OGg&-_1&ztDf${|WxT{^$6Q z|Ns0xReq2DKmJ$vAN3#jKg@ss|Ht|d{KNVW`S0#O=0E8FhX4QnkM9Hj|GA&sZ~mY0 zz7#)ZKlOjK{r?xmW04mMR9_!NMZ%RA$I%gRrA6`dL|iFRe0>oY3QHtB#3|?6AYyk9 z<&aUF%m4koZmE+xOtVPsP-vIklfR(`qJd8R5Shg5=kJFS1=T#0c)%EEGk5FO(3|?M zGFpJRu|D)p%vipupcnDMC~`i^AdFA?9y5Ty8U<4TAhLjp5c~Pb+dUeflqw+KS{!pX z+~`t9{!^am8QLYD)bL|hoXms{11u`np=UhUSgpB{&}NKvc-XNEjU+q3jP zB4G!p2PLjq2J{VtBcDc(xwF9m@q-$v3ONd-N=i^Y2c#%YL0?leQR0taEkhOEA<2e} z%-fgM{1g@pp$nX5S}Dg!f7RhI#?sD*$%Jzih_xT5XUHSJ#|Y2`SCD9H=T9MtBtt(; zxGYFLdC3+e>n{kQ_IdZr)A3+O`v6HScgBMO6-bTlrcM9O4boL&;TzfGWEz~m z=^$k=^SoE||2TH<&Vo+SUzcWr^_Pe~>{eq_K8^30R|Tb+q_n*?1}zL8Q8Fi`faayH znP!BkGJkLt1&ub$$?d@mvSzmXoj#da=JLi)qQVoh00-%3cR+IfguA9m1QNEo>YS=H z08_l=)Inml2dH0njj+-mh}3O|&?~AbPCXVjl$-oRT@&nqY~TNE&^4aG75??9s5G*% zMjYey2YDsLvmAMieN8Xj`K7UAlGe#hwlXp#ow*b7{Ixtk+wM++W5^h`k*CtB&1>sE z4WU5(17M5ierQW?0l7?58?jkE|4>=X2ilBQRbsvxN;V;5mJ2Hz8nvxt{xMsBRHC-> z%fv9{KIfywKC8??ci=W|{V%km!>*|@S3Np&p1m)WgB={UM~?%?wLpc1Z6P%=m#S2J zNVgmCcn<~>j;(CguAXHwmHX=^zY@Q{hKtrpIGAK<*!bx>Ljka{>tY17-v!F4N=T?DnvbQH2$;aPfbQ{>z4?=G-5FHMHr1 zqWJnEDI*))?(3!iH7r4hjL;(IUZH!X9f(k2w0AuCo{;oSUrql%tPKb1X>VmNg(3nF z&v{YW3Use7YMYgdFNC!Z6of&Yn}mAx`&QI`BAg zp#kl+KrarpltCg(8wf{jK)L-vmBEl}Rh;~uCtO!vEZx)wWRrugg0X510Lf%Bg6H^Vfst^^iXZcOZ&?E> z9lA3{Vwt09JIg86P!bR=;%Ki|z<{_(X%~@QO`%cWev?F3Io>c&N8Mj+ir^`Ivs=r! ziLEJFcr>tbK4MN+&JpF-{@Uzk@`_#ia$Nir&SsQHz7#)BZlI;AqxX>w`01>*7OD5d zM*dK+iI66tV5u@mlT&_5s>UjZN;C>@ufvXVU^?76m+vtKMD|P9@*xEwAxzhLqAY?N zRV}w_Iw?Q%EC-lDfEE9xsCOg=Zh04uAWZv3payWb($QEV2;w}5zP;d?@0#R6B0Ia$ zS@ENm^e8!Or%mlq(ekZTlkzDAM4x_M!kbEYf3kr~?M#aFdef#-#MrhNDN0dxb_NLr zCggdc58%MLeY_nF0j@7ITkLd9#!JL3UmZ3NkCc3TZx7d@DZc`FVFP7*(S>%|%N2I*q3d*yCW=)JPrR-a`<3 zeAF~XOI!X6w_$xe?~#94Z(in94QvGMiBig&Bc$%v_h}>FDBnhbrrJd$F%3Em3{-q< zaggKaUI*p=atA2Jj|w?ygvstlZKIr+IlflWzs3G{J7iYcesZH8H)18lW04l*Ig&R- zy_Y*=nwhq7yrs?Yj=64d4+bpWKS#E1oe<=|bEOCd#q1qMoZHn07|%;{O3bv3i7iYwYmZMRhE# zDQ(@?!x^;lN3l-rfg1J+{C9AelU6n()v-_*N8qQ#)>>2yE4sOPF}nS%^8)d@GQ~)8 zxX1SDJIDP%aP!ZxfYkxnS#lp!IC-~?CEC%|Kjo{X03|b#70^dUjajr#>8~5zSLURg zEVNHAFOHo0FxSxA(Hevy(X76PF0yrDqpK&(3Bfk*BV%b+2cJf@I!k_?%kKD|Ov1p@ zZ6gY9yx5(<^wU$6G>9|8DXpR<8XN(rHY3GcU|gAYZ>|vRdWCW}0PgvmwAUvpQH0{B zM1H7%c{@~xnM8wDfb6E{w{evoPJ7ljVAb`bR^BZXKXuVq4411Ce(7$*D!xaE{mbY< zTS1+PK>xJg!+W=7gj|k$2gh-&-%a|7+kPU2Vvq9Uij%BZ%3ena=-BknwwtMJ`d?+~p;*}8QKGV%> zlK)=0o*wWH7y2GesSeQRuSN*>jH=u2EjC<4fL9V?^7P<8VHqbuk)=>vVJLgJ%{zw0V6lA{9LC`#lRRbt4l87YC z1&ANSBL^4#B+K^BEL%j*gz{T=@TfK3OjuOH280WRKhUyD#TbVV2Dwr45+TlQ(g^lv zEs3Yc8bH+J%`Ju-E0Wd;ff;~v*bvq?RUl^NQdp&KwqZ!zFvDSLQ9ee*&P|0C_-)De z%+u`yM4(ID1;*yaR_;n5eS24fm*2|BTVXEC<&CR9bK`N`m1;zMq{3CBtg^-lQq8C* zECO)oRMVa6P?-L9f*24E>rH3wTOacNu$lg20_W$4Dk`J>1aM)`h&{oPE`hw~ZAj9j z=>qDj3@kw2*l36hnUzIqiA$V7t?9OAoiT27SIVq7n1@lfX-WzvtvSkvGpQjmf$Zpn zGDin#GKqf$wX6HQ(~-KCSOe zwto&Kf^NZqqkrXHHk31*@RRQ)3}FDvFL=aGep$Ng9FGnk%XD!e?H17SMdUj$2`%cr z@!t*wnI>}~QQNu3OFNf_!Ul=U9){G_ZLTewK+i0D zHw#XVn`E^WH1gV&)h%JopVma1ulH$5S{W#oKV2p-=FsV@QhNcptI$9me}Omo2WN%} z7W1P8(YVJWGASB9cg<=4oFT}R03QUaRo)d&A&$kUbbzuZOm2`g_C(b+b0I!bUHLO&KjXZT1$!32U z|m)~A~hN-}pYos&g9z`q|7r*b;jB=TE7+f&Ptdn#SVtBQW8ASL2O zuun><^$&`a{qSW(`+^FdsMy%|NceC6GZR$R%!K(j_Y!|zpY8t$K{R^L5l{8pH<=6o z)}n4h%k17R;h3MrCy-)hlrrQktV-1s;oG6*8>6!|q;*Sl9XLv~b(Sfk4fvWbm-bDM zD`u;V5v_M*XLOB$v&UBb&bS;hMn#^VR;m;1Ezz7Xd|FMNDntY0DldB;^TcOu z3N257sflM2rwwGe%2j?4t-WJjM6Hj+sJzZ3zNlk-!e|YX!DF$ z_cC{7BdqoTQINoH3F8@vtVLoeRXLZlaT?*D&NDDSi+JtNe}0s`ty49-P;*Gtd>UMg zvg?}{g#(O1Sq)F;ThH$0C4XSp693bJGM^M>lsHDBPFj9ym2!lC8 z_>FnR|MI*hnTnH~9m93Q25oj46g!>jP11~!zmv0gJM~4fr5n87FFirxqvb!Ih0CU8 zxUalSe{vHhK@~oS{F^o0|LqZpXRpA{A#_8Rc+#hQ~U(#Pexz7g zZ~cZ{=Ii0uzgSVvl)`U+*q`>89Qa-)GD@Wnzp;jJuB?dk7IWz}uJ^s9}@HqUXFG`uWmkc3Su`1x?Qy0d$}P}?_^uX9$e|Z&LF4-DqVC;E6@U*i z_m36y_P_Bc@OPA3pu93UAjC3KT>I{REkYD z6}J=hGo9F@v2h@DVtjUkFFFGJs~}`TR;W*a(4_mG)wj1ZiBDJ8d(WU6$l#fGS0v?W z6=bV__BeXpME)c`Zc(fDtpDCVb4EqTfZP?RrA}_c<2jV#T}pZGSf<<4%ThTWy8H+P z+a(*rAL^;1hwfC=?<#aKr2Ayk?7in&+_Huh;^9tTouffHmeWodrfRVv-krvA&)E(W zUckiLeCyEI3UgxI)%lL*ugr5k%m4qF%{<~%VO5z*!-n-Uob%7|(Nt;lxOC!nUlQR^ zdyWtMx*zY8uZ5C2Ib53!EOQ(puOgDvtC$2k%a05*0r9!P)sek3U@VllE_y|6k*ng(%dx1m071x$)Cca$=OjLQ<&jQxoQG!j`i;Tul9pr9dv9S~U=}8v4$n3;hpejfe6S%kFn%px9#rqw~ zpH9cow>eK_#F0*g=RM)fA$C(*&v8iFGbv>*UlVpP1rJrpNR|B-QAF4Up%*yKzM9BD zgNH!{5qDf1a?j~td$({GD(+2gFxUBxmVdpmVumt$c8$)GmT;In)%CB-4Q|wq@BEt?Bq zjU_KK3m{-wD$8jaGL;y%Jg-?tMu-oym6w32f3ueCe6DUHKVz^Oa21 zv~|oGo3XLrR$Y6sBJ}F40WaxMqv&9;!n=RDv9tgH{{Loh000000%*v*c$y^*ihiG9 z?cyIGEUn>nn>NNUgpfM3+S&)nbp4+oZAmCzmM#1n&#)xO9S|`6nJiMeoY7jW0>`Ij z2d6f?e}1`N*}^$*_+t>GS7J5O=hPe%!$eU_;+b#}rEF9jGC#$Di{Qa!BKl@@d*>F>=k^2n0yw(SecvqEQz^iWX}Hck`d(* zx)i(uM&@QXxh0B(HG&^Gqo0ud*RGACjt)*9?xYSq3RJTIhXdA0Z5|N0RG46tAq zj@6yLHxdoBqYEf;e~uKbe_~gFY+m$v$_SMbm(5zCX*A^f#SBs`hUQa~3M@=474_F_ z`_4?O0-x6wMF1)alpw`ki2dmYwFB&rE$TrH;8y_i)`J3D>6>am4GbVbKs2K{BG9D! zI7cn(FlB>I0xyZ7g!*Gn?NI9A9%%>(4fXZzm4V~w@&6{a#13ks*ShK2vpi9)_HJRaVT6Sy&$okU_ z95^@Xf1bQdT!1h!!pw;bB2X3^sAA;2jR0qFfh8mcS`{tDFa3Oi8d_bu%Y67NNGCF> z^4b~~;;bM<*VX`T>Bq#qXwpL_Q@oJ3#f>?yXs9CHesIG@z~sCQ)NiZjGFJNog$Jz_G{UR=?JOcrKDhcPW7n=!{I87RzisB( z$>VUHZ}xSz(|@h|e6li76Vi1lab?1(k^h12|H*6pda#BrBD!a^Dd9lIR_Td{wZ~fQ!$u)ey45W?xd@~lL>xoyRk{TK$(QHr zXyG^9_HC(nn#6_o`PYng{4pWz)jl+Nv5G;a)tUw`SBi~uUSr}V^!;fIc-v_OW?uwEnWe^A>(eEwZLml1DEIx5VB!uJZ zZehWHq*&2!zYS=E3n+@Tru*70()6~!8k8xyNa0?D1j5ufePH0w(Rt}`{-GuqY6b@mp9>xVcxBd)8Sy$^+;3b)nuEPjP8IPc8UwO_j6kj;^xx90fTX~(p zClUk)fZqvc5-be5MHsV{2zl2(RFo>5H1gPo2r;Zcih8~MI!5Gp5G73gE+(HwuyYRB z#|qO7A1W)hg4Mx}gd1NTLnEYrt8`(n>8*Jh-07}3RTZj&+o0YK#Ba;If?V>6}=IpZ^m*ytFga`$gze7B#xCrzDU5GSS`q5Ww#!#vvTrME|JhTN|;Q$q>&Z zgPRitbfsT26~tDk5UvOx@r%icg2|mR1Fhl(93f9YIT8ovYQIbu#ukEW+>WdFjRUE7 z_24UN&96&a0`DWj9;ET5{E^5i2$u$IXbJ$DWA*A&k_#}D37EO}0PWv+&^ni8c13T7 zKP7XJW_wm*seloTE9hLz$zhn9Z1?%E8dWIJeeIx!lTL(wbGdwkrgIZKNS%vqQ$3JA%#|G2}SVzG3P}zAZ>Ac|S9%$(S zgfcI|l6{OP=)DB-&3tcXd;+5NVtryWX$}0wzJ$M=n`t_I)o&D3cL@Nmpqo?E_jT*0 zTSjcPQ`w&xhs*f98vIAGhab|0IePYovFB2itap8bketUmOzMPji@7_n2GUjyb>(~_ zNLH8cMht7mgsW~wu!+7e^_dRnbv{KV57CaWr6$<(vwyP5PDtZd>80+4kS=M)Xi(^s zwA+1~RrP%>+{Vy?=ESr9!@zm8u@xUB+0lUFHVpRqDR-91Bl^=`%I6{sAn(;FG`Pup z!~JFn3PM$P_E=x}>pR>ocx%FT3W*Y)?6}JvZ8r(HU%4wb7(VxS!6mYnf$pLO_VI_h zG{D3lve&K%+iw=VAw32Ez*WQj;MG#FAq$Q?d2r~}RSf1-5dQ8nPi*|NKWlZ<+J)cJ z%s?Xgi=Heh9A~T&qa3@}f1?A}BQxRj_E;%NGe>Rw+g$uB2{(Ztj*9K0!1b7y7QKYa zoDVq9eW@~jq^LKW?{4kZbkVX~`bw`igc1Z#Awi_t2wStawwxD^_SXzgC#=sF@N-yq zcl!{%5+uQ%Tpnm9O1hUBn)1inVEF@?DG)I+M^WcylsG^e%M9-J-SX9Xo%*OTy6VeT z=w-?Nls_`l1|gLhR=sx{XY)2L*BZb?w!Y$*{+dbwU->h^p#zB zM_%y=tT^FVjS>|F1JB7E_hBus&+*yyE%%FSCysQ2l?~@Kz2>y%omWU0^ajeCyLZ|p zeFQlWgx?)rVEXgcix^FmjO_m-p8v?N#O%8z@2Ntu_U!ikMr8u7k=z}n#0IYd&c=3v zl9l4uI5)X}WvOjjA)ZqJF?L|wb&Hk(Wk67%RXtpB(dcpM@O&%`BFu8d%{Fp&2e~*H zCje8;;X?U@J}#;$fAkxC>v)H5roE4~UsqFC0+3&ZGBr;WRkvNGSNibR*C$V?!Rf8z z1wDAw)VBtsTwDhgo%}2N%=*ECC^CAqE>! zo52RbZ5|j&49<%?GCq_fpY8#ZR6e0*T6XumXu^Sdn9TNrsXO@}6B5H92$t2XZG1WN zaDCA84Pj!jbA-n~z5ZD%IbEe4EHfe2n5^!d%ks(ptUVsFt_5)p#B_3B+Vkf``~gmf zOtAaQ1Z@h{HWBZrynD!Od%of~h6%Kv-Mf5aAbA#_!6i@pF(mM1rRD!sPZ^EtYTWqu)|E^JB3NnwhBA&E(V+gf0NPBZOaRPX zx{>@f5M))Y0OrboHNA#QP!8YqGZIL7%a}AD`kxPsA*hloP_>P7_TzK?ldG6=_2(o3 z$?jVK@+MM>urD5$o*8y{_K!Cj9~4Wi%_J1@QD2?aD#S=!cec_tTUSCY(D2J23#234 zhP;L|wk#kG!&mhi+1kV#jW_jj^?;HIm#heeE$H@&m9bx-bj%w501CVwn$)9IAS5K2 zex=&NQksFo#;S$I-0q$nIz}yW+Jp#!RD|g1=*gA_JZwfi@QZPHh(v+(4^X>RST$F~Tre?`z5$a` zRzim+O^y9NdRa;k=KxY)iU(VQL@k@HU4bH|7E3{KpJKCC)PjUQWRix6mbT+Aa#!rE zGz{}H1qf?_`D|=)eax-(-;@nUJHVVLg`ru8k z&jQB37=-m6w3@dMqt+YDcKvj7siMSA7IsYM zfN`elanT*5Qh31Gc#JB0 z&D*%m6_8VQ1JBgtpLS2=4pzz#VpdYZ@2zrvo~vwC1*WsgO3d|-2CCU&0+qnQ(<(a}77j=oY(bQ=xwW;tS;g|%`SiE|>l zp-)zKtY06u3HwXTU@_x;iA5vp<;VXG-;Sh6+7jUcfNC>^>Hk!MEAfmMRs^Fy$vw8# zh&q@IL)&RFIFTl;;l5b=ERzFY0}8MovqF*y@;;3;z36ANoJ1{W!8<{y&dHxb+LEcw z9@C(x&XCduoNFDdJF%aiGIliTg7M}eo(>Zf&}yMUm2+Caw~I$HyKCgMxdGRcGX&O* z2NJL}r}d6MS*Khi8nIa`vGFA}8LYHUl+aT9w=MAYsQ!PsRz=J6~308KR^ zit8V*`v*h_Pk(i2M1tWh9n26g^xSsHNI0~X{{=SlD9!H8Y9svvGw8H%6HvIt_dPa< zaW!p}I=cuNWht`ZP3Z>B*4EAp1aY3kj)5Jykc%bVJO0AmF9DB}O7rZ4Wz`{td zPQWgkQQJR57C8P8EBcKoPaN{`0u&9wy@n8OHuQUu;(uS5?qv3tbSzu)#8H-t8#u9v z*sAvAe3-4##y_4QazMU<9)jTgLw=CWECbs{>RR0Z1vRCzbdGr&xAVPYjYLBIsH-J; zlU-l5dQnzb!s5Bc%GLCj*yv-_y|g%3wFUZ+nE;hC4;C=iO+S3|KaWhrT{wILL_!^O z(qYq=QEg6AuK>wJ(R-J4gu_w?IISlOCGGN|b&^_WX-C~OjTpyUHz5)rZscO!l_iFP z$11miF=mcG5hmv0Y%I6Zj|gI}sP!FB!BkcAkt$vTH|Iw_)7nK$;E%Z7L8ZCiOe~os zlh~<^*+ZWk7F;fA^k?&RMZUf*h%b#kx`L4Ou1Nxg9k2iZ02gM_dTE2=?tF4Em(;_b zefe2x92=fuxQ{rg2sbDD3xxPxLd z$u9KO2e<^nkf$4JT*l!uCCow-_{5=fg!jH~m!-N2Eib^Hsc5;LVSfPhm7&QJ2p;8| zp^Zz7`y0xbEFK)`cx_{bKv03B_620wBPKK;(|HW%Ec&xG-rVJ|Tv2}jVPqX=h97i* z*1|n^V9)|i`*0-z$ClB=Ah*lvcvbnm?ysZG!9tNpu#Gf zd!0bW@m?Ye_8aRB#aLRmInQb;LKA!gd(Wvx+W*`U$lTpLk=jw?m|sE=7CNZ81ok0@xiwl z9|)j1ZDGv7`#%G7b+x;QyjMnvn&M=@L|#=qIbN?2?=#Sz266NzgZKJzlW}|5mz>Sk zevUij3;iVt>Vl6sLREY*!}f@Kjj$rPzjnUdrF-aGF6|(dQ%=usApGI8B>9ie910Q*z-$AIarOZect)LD>|ja%L7A*-gG#0$L(C zj)LLHbJg28)HD2Mw>*sxyNnft$OBqu@4<<4dTlhUbf)+3_K3SCr*6e`v>d`J%LJdM zG3Y^vD3mBpsY{%(HLsvE;wS=%QA!OPjuSp*O&Ym_j$SwoTsLUg6sVlMx^4M1cPCnC z5pgZ*tI07;H(Am<*uD8-1LPn`G$90n+}<@Y!b*M53Ic zzvIiBF+-L`@MhMC1}r#~l;&{M{KH+$0M2j5)O;UdW3aT~o%!mNvSg^8mBr$^&Y9*J z=bi>vTC2S8ESLsltp&<_--L&D+4r3ebDhDT3Db;y*15pmZdjg5M1xBNuFBo2DQsf+ zW`-6HHht$O`?yb zK(som{FbhSjVvi{;+fQ<>H(0Na(V8ZXDxmYt&`zY5!m~p`i@v^rtStY$!1HORrYnb+ zBYP6bg#RqUPsV^kc=H`lUJd;xD?D7Axz#)&sp}i(gn+K`{)*4)o_H?h=Imp#0(xJo zo!ItFCFa6GZ-dxyn(WGip1d7mldd9R z6Gu8krwkgd_=}{4g&%xpH#eKuocw5H8Lq* zVe%(;eYFE@@I+s<|6@e2e+zGw)z}7ARm{75|o{!Kt? z-a&{I0nDU)uGMzN#52@U6<)iSyOE1*(h#{LMFu+l;P(sU$-P#wt8&5+>MlUlTd+WT z&wo)wavf4hJa=? zK}7CXtmQHJhqVKYX*PjE8T31JX4f+&j@TG!bx-C4A6SD!5rVbIdQwW; zOKV^xE3&PwKPfjQehv-T)Y<%i6@rL9$S~PCDC^WdJklQ4j?bRGg<${YTH|(~a?^Ws zVDfY>Rzzf}d0-QC4`zW;exuDs&5H(ok8bWMKSfCIydUnX>U2$)xM3o^jsC`Yz7P0A zGT2^XhDPpNk1}iUsCV^$@Dy;m4NZ7u#fMv)rFQ}m5-GD^{(j+!qS01PGXWTwb1ZH2 zr{M$clWC5P`vb;0F^V4kT zawSAC8?Q@>?iQmmo#h3PKV{(biZ5wiiZkO=jfrwHb+0*(TG@-qsCljNY&SKC%9b3nkHZ9Z;CA?^92H zuOS5Q&02o!zjIuGTi1dh#|34|x*l2}5t$`QniXy@%-Mx*zG$;h1 zo?07`iLJ+)jS}{zY6ni&?;u3ye(0n0i9XvI5Hv0$c2xspIm;I5#*J{$2 z(D|(U8X=OtXAz-x!sH!#Rj`$2fc7$4G~(})h&H2VVS-93jpo>=X!~&hI)2t82UUlx zo)-`s2{|a#l5Tjy1qA^uHQ-rzeHnq@;lxc^ogRc+VZ?nMhWh9~rpTw@{77L%3hKEl z6Sbe@sR$Q6{_=_p@yumnE0&7Lgj0vLI;I!#1gdUKi9(fO`<=8PV8WL8@H zt>LF;7rxZz;vlFlk5$^HYsb)n0Q$sZV6eFn2`GQ85i~6h08k_VgGc%nBVSpHSCgqg zd@zN;{ma1<-2iUjvL-DBMydsM2)X|flHv!$+BItFpQL;!>~uBaHve!)SxRqMztDAB4+Wwj#~rM8Cg$b%$pkV!l>D3AIFaFNZgcdZ zPIBIVV_+wH?Eg9GYoz>EqB{Ey=?*?+TFuEvjw{!zQ`=iaLJf#T#xdo=0o3;JE5y~E zr5x(ey4>9($*nv4WBoHt)$jre7KGV(W>pX`#W@Wk&*b30ex2MGot(M`ZIFsTB>P$FHl$1_;$f)Ed%2z@nhN48@XdQhcLrezJK+Y`k)wWnk63r zzDN#RR9L=5VcRo9nLf!GHzdtLoTsySv1p;8<9)bV z&I@>xg~jW?a4nYkmT}Ku82eMw6>})5IrPfE7&y-6r-N7`G#1WwizggSF`Ne5Q3IC z#R!I#XOH2iwA|#tEo_+XO6gxYSGKnaq%^nuTeNufdB2r}wsyt`&Cz2$4%8$-(rg&| z508Ki`564w`JJ)VE{&P%Iz8~V1ns#jG#3!9_s+7NFW0f+FVH{!UP_n$a{mkNe5uQK z9Nq-QzS-|mBluopy`1ASY(kUoXs3l~(dFuiMguba;Bdk_sqZLesRJjxLFt`kpfUG#&?e+%XSM{8Y-?3G|!b*GmIsW8gvxx$^Y0!&Bz9BAzusK zS?zLi+{Zu43fjHfE8O{VsZB8VW{xvicn7ufH6*h2gQn2S5Z;a-5P}AFtU3wZIL{9%A8SQ}Km*TgeeEt8xH_!_JloPS@^LHbz->jM>7VaMG8P;98 zIkVHM(}cSA;}0N;pwo8N(A#Lx2QgH1 zrsC`xWzge2H8%VJE=${P8`8Y*<`LAXuVSM?N`ZZ2w}R;Y5H8ruPwoAh*vW5jzh`2f zYec7M_54+%*Zl%jIK=3@J9#6yZ?U@_ApHZ60qQ zU3Ls3jkYO(esiA?s=YpCN%cai?|1%?WDw+Ub2a3L-t3Kg`crWLCZJ2?wS5vr=@bDz zcbmMN%TJziW2-nbn>aWgYr`WZ>=Z*W5Fo-@$nSl+@*eu#*EjfjP)Lx9ltmQYyvHh& zZp1W;CrEa|N|C8oI_^|GtsM711o`qnN+tN%w0g#OADWO3pd=8L<0xo1E<7Ye!!{xL z_dezZR%w-oiI`|YNuGP2z#9q?7VB+ zX88%MxTLZcPH}Jdm8=TSB0&~r#)OpYby4SJBCwqWqL)m2%jdKRQnic%j`0~2Qe`T& z-B)cW$dc*{(=oxn%HW3_*5h?{UEDxm>@n4$5uqrUp0n0>(q zTJ4=&PFg2sjB^F<-N4K;EpLI`3=k{(9QH5=&mP@PDsTXLy(AP63>>TI4@K#s?hqce zij4{aDZViC8*F4u8nMBGlfeAa8<2Sz485JzOLKyJR8i->lLB=ey%I<=M$8t@JU@ zWZun|31!hw^OErf)2AcwN3FJ}2KoS&6^v_-pAkcceF{h#QX2qHxU&SJL&xbpn%-eP zO!dj(%iY_*VT(`TA))G1%wrWVtHhK&lffZ#8uvfX#&c0U?LQ*=bM+l_UV=2`4wv5g zvntBE_=7dmyn4pPgNys;fp`4^H>63p74D0za;mq_BM=C+6yV`5YiU^)$9G7aWqxm; z6LA(p0#;bJGr$dD)cg|v$;(1fK=)Ly?0tt(E1Y$n@VZI>J@`a!EPH&cDx=Re(~M~N zh+Di48r&14!(vNRd{IYrSnWU7B?L8?uvf?HYQ{Ck(^j|8q*(ZUb2f{?p;peM63&-L zLQ*k|CwGI!0{xI^##L74LE1l+F3viMG(WYegxfXDgQ}FIr&z1s%QDfyU&WPu(>U0l z1Kz@sC!RJ^z~+IRd3>GT55RK?O^h!l7~Hp(q419zp9aUa;qY(GF5d?HWe$_t!DiR* zd?C-cc01ncBU%|1nScD-(j4%g)|LfI3FL$ulU7>`iS@g_f)Vi;x_v=9i_3PWeSB>; z=ByISRC+ZnU`7aRt|66*TJ-uBU<|);>R1u@l0o{8vOOO5Pw2N|J6)IZ6Y}S9k*F%v zR-g9l`UiA`B5$*#{mku2*_xnGzrjjtC7_ba>3h^b;1AUPfdO#=;KLa_c57qtq_@2? zAcjX%&LCZmuZ_!P5b;BI(3c|zG;^|x^G2gI<_Tw`&~LAs1A8UnttYTo%!KrX&LhC% zKzo)rN4i^&Yb5?(WyCmvQ+rSaR>BuVTPoP`J9w=KR10165M+k=`Q|sa_C=h`=MQz* z(9Nn_eyC-@MNYWaN<2`PKKL%>W}Iv_+i_`0I>t4ey)8Z4bKsAKLl7o5z~On-j?C)h zgB0se$8n902|w{t3U(Mg+Fi*&6g8gG$~x*W>8warNM${m~|ggO2eiW2u`3c@DCRhj~@0yIGeR}`8#*!u zJN46^B9BSQvD#=L%DII#;a^`Xo2a#)4~-#8%%6)?sdWg35I#Hv8!yA2rH^dp7T~!w z2NcN0x1e>q*OlYWGT!wqRtTE6hYZDCw%l=1$6j13|ioYL4acdVLn%oni zR?*{l`T~dc^LtF0J)YtTHY%WfhZhQ!q3F?u76pvr(=9FfkZ;L z`n1u#!A!BSJ=obNc==yxgUM0054`!G%16zTeP_r3tSV-mLi)8U09(5PA`YpGiT`DY z$64C%nn)KOU^rX3r|ZI2xXw}whrUaJvb`kLk*t$2Yo<6$-PH57T>?La68B=eJ_si&95|XLNPX=SLgX(G<#iE;<^xwQjQlS2b5FM z+=$>Qrq3(RN^g(Ea-xq|#~Zn0#$)#>!wAu-?U4u>cw-7n;p`eM8h5N% zZqxA|p~R9DviuI*Du z6>+%+pgqmTlvc((me>>^2C2p1?JkXekfaT2lyIN0J_pHtwtd!1RdI_XmDl%xK#q%; zeHgv8w#%Q*hf{O;TLG?b_Ki_O@;3%Es38)q*I=$>fT+dB>GYgOlFI*- zroz-TigJ)&5w!QieVk4AFN(1iKvjX>Pwrd!uQtSWxSWC1C3Sm=AcbuY#SgPOxy$Xw z=S4)e?i$^+3mELZ`DUrGej@`Ttv3LvHv<`0)EUw3>`i5a*n9V621!RqVR=XSyCL99 zPz@)?aMBeL`i98Xn{?l}>lw^@k(teRjGFSyyDisY7@dC>CNW*EUaRWWc_yKzkWPrR z`i376ZOyc6Xq~VbZ#kNy|6H;pw$EREitqYx8XJ#)f!b(eY(bjqGfbW3lb|?lfB$%NfLPV*I#1#Ow7x9jh=ACrRW~?v1f3)$>9E?YoTUZl3~bd5wEj+5ux^DSDl5=^G*NqHH1BurG3(1y{iCFX{ z;Z#+QY2{^zQSpM&1W{%Vg2;!Qyp9Ml4XKQO`h(#ar){>)V#$rS&8~!QCfOq#MrhAb zXbkoCG8r}jGO`iEx1OBQehCp~Or;6|1tERoXTsY;EA<({iCRcJ8Q!Krjiep){FfL2 zOzFLS)Y5H}6n1fS?lXhV(_Zc@m^dAr2VE6`wSRho)`fum?kQM96R$XTSI>7UA8 z7MZINz@RIrI~JR@vD6qYJ+<#I%elSEj$!5?6jKwUs*XyipFt-{eya5_oiVR<|fc zs)XY#CWz*riN z5j(jj?~+dOduDaq@>7k>^ECwY#vp-~4{lrX`r`TvYc~o4HImg9!27>>0s2#*{uOl|%ognO29pOHp6(<>CV7Az`y$nsrk2&Ugo}prpYC^7erpub@oF?}}t*9K1x!KoaOK4MQGS9nzEW;QP!peJu=$m_P#I6V5`yZN$ZC5xyrFEI1i@s3ex> zI)h!Ok7pndeUQS9IjfQ=Dq^cBrqy{NP++Qwmn}7W$Q{^r(Bg^<*+@N&`E913c3fj* zuw>V<=fCfl2-Nu~d&ItsVHY4NRSpM;=a>RCQ(Tui`P#V?fL62s?IlAAJn%SU!ZYkh zTkr#Zm)4C%Q)T+6WpB?JX*12XBRXFyQ~CgNjS!NP>-Ca<9g5U}M#Q565#UuchzN}Q zZf**O6V*|D7pYc2wD@v__mDv7v-P25OKxGRKq%Q&Sibd;)B~hJ_T~2ef~^}Ob?OPReOQGh6p49# zMT#2)J7J0*v|Ph+7%hEprE*R<BaZ(~y zKI{x|@AamtC&}PX3W071(f~puto?iiN8qVA@#vT| z`5S%a^ovZ`#wN8>^rgAtZi;;8MU4B_5P^-Cl%U>oGZ!twbp)Aw7g9E(=_0oR zn*dDZuk3(;HdC;A2%UQ?P7n9fYk}tOSqud@Y!qBrH{r*|%k=oS`W&`{okC~Eyfr1X zK)0j4wSJD$?qBQJ6K$BQkSQU%;VUYUb@JPp8*CTg7*0iUv4W$Q5p8^yUbCJ!SoMcf zVf6t12v60LCE&Rw49RzNYy1>F7^hBaT+pf=#K)O5!BHJz|FdkLboq-L@7=_C$;H18 z3Lrs36omhEZsnt_p1iJO3nUbi*p@dhXjX5TQc-ham^R!4w(tbWTI!#>+cj z6M5J;DF(in*iaNU4a#^|P~CEo_!$O{6tZ<5z4!$yaU4 z(3k(Wcb>-*L~SaO+|aD$AFUO;ZiEj{byyo+Aaesbt*7H8k9_pVIO_0yO{VKe=>lhR zM1}X^_T^B)B3$r=zYMqjXgQNf*&${cL;)X%{wPE1f=gNCeb>#b3Ws`HWil*J9DsW4 z$!k21#u>GYEgwx#vL-NbUDg(E3Ui-nVfu>uY>In1tXsNI?nUvF;^+W+Ba>I#X?U_L zzzfsP^!$9hstVC9t`3eBc7`@6e^en2PTizp(56Ds?!TN}6hHmaS)b~H{^e{~5FdiX zp6_whxSxOajVwWs+(X+-OwV}+<@m!ir+peoB2`_zdn!8&KX+_Ddy|r~T>P_7Vz8DK zy8@jmc>e1s;vtXucC3K>;UsmV$C*(yi-Q1vK57HI*Ei^6!zoK#>2{jK#G@R|9T*kK z9XlKC@@$}kw5z)xO{hxJvZXV4OxOD-62MxJ>+MAy%b(o1AB8_5L8Vl%6eVKLYGly~5bUc$`NVNf( zTU~=C!;U!CNe$5D{G1}zYo-j7;R5x7pMPJE--CrcOACWyh+LC?{KE%^j0aXiX~7H& ze7j`~jEBQys{lgr?8<9J78i8mTORZ2t&eMI>Zm?U>r*iAcm^0lXy#MYYP0Qj+o;`w z`0gOJvywP9{8MwUJRLy)2KCdL%H^}i{`A940T~fM+$+!3D+@_s$K#E};CKX18?QwR zAx$ql0>M9t4oV727t0ia2JwPG$bIGc9eHE9HN_XTLlc%!?x3c9w*ZdDxT}VhOU71e zUyjZLJCKDwsz?5WEvU_tbdiG6g8x&p;Mv!^j6kLRuvu6!riv`U3xsnVB&VEc#O8g^ z4L7jNu`kRNulZmXZZ~-IO>KU44$pnV#tFT&iDdQUC<48sK^rZl#q)S!7MQ`k;sSY@5l(ef?HQZ_+y?f8tUM1lO zMANKje^Z4SsA>MwAcIu|DwB`39n1CfZR6mNQA$X&bRmo{S%+28zWkOs(9mC|ejKj| zNC>)nGsRS!i$`>8&Sx?l3@4uUY3yW&_wTiL{pY__pXeUq-OcT2+xZksmgcDSU?4{j zxUmSRBA0@SMb5dJ&#xn2DMA^?tBad1EBqRy1T-KhlgbKFoc!=b(xs>%8L~8gv(}Wm7!SSIAsdlw zhsl2~_RjBnK5un*fC~?}1M&?ZWK`ETg|)=JqJ@81-)ppoO>nT4cix)Ko{vg*kQlkV zsqz=!aRT>9eyCWR4BDI%dtRjU`gNZ9@x=zP&LJ1n!~X{9WRdjCM&zn?#7q*;O=FF1 zj^8doOlGK}U1}?VZOs>-SzT! zwdKRftI}Ckf1iwtFpD;Iu zfBt9t{i>RV&b6?sF1|T(L-WpS^A|bVJ+oiPmA*#mU#yOL*gq+y)%e+4CS}(CLkT?LoqKY_lm+bd(85X#uEJF1!#2 z*_qp%HHUKi0f3m=P*sIy!40T#BgZrCuo@5Cyi!VSsc-Iom7L7?)DxkSCouJAJ`<~l*&PsNQej&a{0G241|`V60vZNGG*X758E{B zXf*p4sX|pRW_&3~YILIzib0#&o2jXA-Bx}6^oa2IqfWtLjNGJipBHB6^V+C2>C)uV z@Gr=L7m4m|-E*LpL@zSJA)RNkIOGY`NKGW&GV<#hTx0*cKuxHzEK0hCXzLye;3X2y zfxzyUZF1As01hVrT)kz^d17^f3S4iXX|vlzIC~tBk!Z8{o&ID%FSmO*+GTR zv6T)9QS0h@H8f5l~*)MeS~D=JWS?2X1~Z@`eufu;2H<&c`|t zYI%+KuN1VMkYX5OaVQ3cZ>6bjAu8pI(dh=5;9o0m2FyP68A3>0sqU z@wpzkj@wf4HHi!hCCX&NAz2p{J>F>rSMBnc9g6LJyy#+kX$k;^a^k|tx4dR(UOTy$ zX=Ug5alT+dlwf$SoUb74bzpUy!7EI(^63La0@tSx8V3BV0;| zIEV=YFmUoITnnd#gwS5Bia(PhPSsCngIT~aX#nP6d-qS1N}gH7AcJ zL)2dM?Ml0opLHXt%}tdBMo1aN4SA&n(eY|I&y#3)Y$26<^kkQ;Wq@=?Id zJOVsW*L6Tn07bG&@zy0Ezbl$p0ZRp2qNM3#itv!tFqXtWui~>H&!(#X;n$E;eIDQR zT+WJ`XyP04c3%Cs0Euq1p`{Ncwy3aG``zx4qcQCPManK1%meT+VnNRc zu(I7tZdlV2H@O3--Vm&A}~~Ty|J{G>3X50hs@$t^@P`XtJeFLK$lu3zUR*#OT&}HGb=f6d*g&^^a&7KQGY@t zR?U%hSp`6&8`{2)o=bW8_94z@Yqrxu3uiv$=rFWx;1)3V7D!HX9DsBu(rXR8WeuOr zyd3G)Q*mXZ(#_=3dWLjgI`s<Z<|Wrxs@z!2e%a6=Kre zBJW`=%eoYGLgiDXlD6d|AYeWH4{>ZI!Bs zG9*OIX+BddTebt>NxOi0n~NkBp8!7nadYenS6sd_!n6`d1FLo}ei>nSPDzP;{DAjj z%gqjnVhg)PJ%a{-vrUgxyVme$vtiaC^e8HR6bnNa3()fYe(3M*0EWA~{pkSmZ8W%V zG$d9g@x~6FVU{B}DFJc9D87uDB^8{Uz!SmZM?rCG;(RzkO|t<4W#7x{qSiEb9*X4? zF?tyPhpo`CExnV|>A9>G^IE$6f6WIH%iTzX&V>b0_lpTDBimVBAMQk1UF`kUEom+w zjn(3WLx9*kgK&KFH(xkyg{Ai#&{QD*4jGoyaKwB;I4fVPFFTaDDI}AA(0o>6t);3` z$zhWs>j`B)FhCUEf%wxK>gn>WT>1q@Uuf4g&F@K!D6t0r!y&)SW=0EQ`nHqZ^R=6F zbobBLyKmo!APNv8#1mY1w|Ax>pdLr3<%%U3>SbE?DKfcQ=HZK_X5bj5Wh)#1nRGx2 zn79Rmx05_R@hPt)UC-%6{gr#AO~sj3wyL%R2@k``;kBaxCq4MC&1&d!5yOorA8FKK z5CH2|_ub*5*APwakhUg~l##jSm~@r4i9BPYl-gUBU&mh6n_Ng`0@-IAeUUSz=?uQY z^{Mv>vU#9_(8KeW$7)qOk+@7kfvX73!V2<#c!w!s6Ov76g#nyz+R~OeJc-La7SMGw z>hZhyb3guRc>SwKGHyJcHfl{0$q#h9!E{>gS8_at{Mnx3qvoa4JGRCFmkL&vKPpkUExdh{!wH9`{Kv!LRc6_4{X~2SplOTN>B@%Z0h` zS`UMp{A;<^*7l_1N6bg~vQqE%Zb`kW$f)!HM-5!_0(D)d;y(T~8z$t|ttKYp$T-1z<5T3A z7|YfwqZLomBv;=a2Bx7Yx!4x-Caq2d*$#c4c>F`)xs~X&=h4NKn1Ye>+BHv3j7*AEGaF;dQp$sQzs-kQ6|_%`@z9J!;4^tMEs*eMv?owULA z52>+de@0?5Mz!3QqXQwKIqUYSIYXnIWdHQM`#b?t&$u1%FjSb3RGAc;Esgn*bO;Uu z{*BQIICQC*QB#J8ef}q~F2OqCR@qfseqgKld}t5(z=^U&dSPtIZ`tqgyvxh)W%f2a zHVtue5OixsA*4kR`=qZ%vOOCcC*IDcj(p*jnYQwE37^pN9r|k&IfW$JxiR}tH9&Ja z48+bxwB>D~4(gsl#C$bWqQIGq9uXrd`m&qLUzEL-HFaP^vWXzS^5WtRssd9T%`@lY zliVDoj&=$7_NG)Y1;XjrTaysbx>(YFHZY`g{3wlH1=i!H!EL@>FEDN$tufm6b~e66%R1muV*dptgVERfli*-d4S1S1_NZ5yS4ZJ0ss9#Fqw z-^w;RC97vsMwg_KB`pU?ZX8lmv@vev7>hG8PnLFvBg}NPpal8$by{uH3wGqtbeeyc zNP8rii9wg*#C(L&#~``7krF=x0OlVigC8Z+#*fb_uYRs4p=2c_nqvV`iNjZEJb14Ck(5 zc^}%TH3PbJq=%XZ$?um(d;^#lDXlRQNDojEvya zWUr-@Vqdc3K(RB9paNpYA-;$k>}nZg1yW@?rP(=6*r=44tEVGj4ri=iE5fo?-(;)$ zmy0VyY>GI<0;w#~D5zTO)HtV`poHNR6YBLef+0N=0<$0q_Rhn=$G}r%Rl1#Ol(z?# z3=;UA0k_qu68JJtsv>+yRLn6N2hG{5ZQB#GbP}o zAYi4S@D|u$032U{00014_?Ic$%YrZ!n#ycqW*}JDl>>z$v-4_oSSm@L9y?%oGCM*o z9~%@BazYnY0_0R2UM@S=NK-0x3hv|NcDmWkf(2m#gN4tK0e!1D_353#kK7X z@w2+LYGT)MQrHm1bDlGK(i0#ihM+5CbctPCTVf)YHa{F9V%bqv(=N)qYY;^IUsijv zi-myWc*Kxfk{TS5eIatfqO&T#)}H7PAG5&%eXr5Q@uF!csxb=d>rIkH#GBugdVv?g z;H#`@JI=-n%K8s3bo976XZ_|>AKIhZUUYc?RL;aCU&$E$fSXk})ZR_s@8oo(s+H=4 zPi1jk221iUW;#HGvkJS#5xigL*%CE1_)Vu`7Q6pPFpZ@ZT{;zups%$EW4s(c%)?*$ zYNCh<3gzb-Ws5{3=;g=eda%4i)w_9XTSeHAb6Q?NFMl_{fwcAhn!=o@yQx;#G6Q7fFd-L97#DW(}oPlRMWXC6Pe+Sxkgj0zS$YjDdTQeqeKEKd^jTmFZuK>|skw^O(Q zh7ybJ%6j!NHl5>%ZoTxd752)w?8{~;Y(G^|35EG8Ne?Lt(e^D4!kJV!-^zu zT^pXIo0rC?!Pvq(>K#V;b=VOK6vmIeu=jRI_7_@KAV=qr9u$*N;jEuKT&;Xpzt{3r z%wWcG$H!oyGwW~0&GV~DLvE0uWFD?{9NxHSDFc79w*;2da)|aF@oL0wXbu=%{)Hj} z09?xY^KDuzv5=Chr6I!DXu-^=<#uoTo_9iJ?0p^CDJ0>aT@stABy zCUe^Rv`#3d8Fz(|WTM=o)>~Sc9ElvoW$1*(k;ThR2=IABV>2wTLte3g|_D3aYLlDo`8xpY%#^KG6!SD3492xdw;Jx|X`A7j)v`h=wQ) zp%~l0=sX!<&ini;1EtN^9vW&&mPYWy4v{OJ*@ppW)dxr+knj-63_XuR3308cLPa~> zzG38bWK$&8`cP2ad+8GSnsEW)JKI%hxktz)=b~gyzsbW`dF-hormVTk!dWJ;Ux&S@ zoJIZ?XD;;InF!+gJ4z@ky+OiM`weM6E{WR&d5sI3WIQ_=e5y)c{>9P22CHSttGFe# z`pW>?Bg(=SPip&?kGOc1=D$Zllf9$&GwY)eY3_@O;`UoDRHCB@Y6%4`t{uO-Xh8x2 zXT0Wo{KMFrXaH|ZUhVnzzn+1f`*S2u$~UQaL-3_0Qash7LSBW`#{n~;dZd(4xIGVZ z6nc3V2t>O}nSDd~Q-Tv$JSYjNOF-)(qpY4665W9UBBe@|nP)Ni0Xe*K^N%UX{y;(- z|GQY?i$DFi3FR87i1V>+IE-rJ=H*EZZ{O#KzdLKTB3>xGz)^IhpWtOI#gdexc8LsA zAHmZ8KruU38C`?qB|xrV8saNMeb|@n0%!YW0*0jka#tpa-I+IiykAswRW>ga0_Bj( zi)N*{90zx@!ow5=y*|n0jaA+Vc{#9LrL^|cw*fMS8gqwi`I&XtM0x?NcAlYR7RmW2 zY<`rCnwk8ESN4N=3@z(u)1XI@I7f|5^Cw?!ITQ;RYmXxFo7ZVA#`cB6h(!(J0ebG(BAP0 zo5cbtj0O61N#)h{LSczAeTaW6Wpk`N*g$eAT&*C>N7FSSj?m#ByhU81%D>r>99!XP zUslmnOcLdeM1tEbjrI%~g_LU-Eu>6M%-#_HOME5!--CFj!*Z51M9`v6=)f`~Fc8tt zGkC)-gVO;q$M6ih`vBu4Pe#2=F!rgO9PvCuVB8hGLp?@Ep1TEGJCaEeC$36`tzLN4 zsEhil5&WxsQwDEC4M-GCr=R!WJ?_N+p)x@~QX+_z&&e)V{^-=I`)t0?$7m0Wp48nR z;9x;b81f|k7hTMv5K0L`-rMHEzjCHirpNqS4!Beo*|O=e^)|U|^4jIJ?c4MDX?(ct&&?c@iJT$&2GR?$I>%|a z>uo_h;Iv$CoH|WmvHMmo><`VIod#ipF0(%}fv$N%YFU3MBV0dS59ZF+CO@1M6RZBX zh2<;+rc7^LY2W!8+a0Dj+w?+T3;`ja47n-ApLBHuocYwY%KLITXdCd&-kRl}T(DD& zwk55;ni;z8ezGej9lqe)ON&V|M_ADnbS=CR+dE39P#1ud+r_gmX}~jIP|R ze4KF98jX;#IyD0j){2F+5{q|H(y%RUYb%@a9Clk9>&cRu2XZ_PtQ*ce#R&sf&bwL6 zG(FjA21ez;#WY_@Fo5P!b|q1DzLb3JQD5JVto*`Uz=MQl&C9ihj-)jwi2sIYn@byF znUTI>V#B>8w$_{og{H`vR+3}O@D7HI(lXMEoHrx~_XZ)wbO8yknab^6;1H%2=YauV zy(I6ZW_WZIh(D?+fs)sVRkob`{?8J+*eT*#n0Hx+yiNe4T7rt!_>5Kpe&p_qG{!`C zJ6}tlJpt>4i)kAec|JitpC8(hH7>L>$-eB+slImlB5th;9cWZ$D98HYMO(G;1b9$P z8gee9+&=gq%9!cUe zEWnaa2x!8j(}o)&Qlu7cw|yR}Ag&pUAnHc?8o&&57wsv9gg=9zW8zjlO;?SZrG@Ur z_%*AKXdWNt{?+dMDi^GFOQo-y%>|NRcfK+Uw`qt@zjYMLR<#w zG=wonLOO^u;QK`Cz4L_&E1~=!b$&VJtxDIqEpbuC+-*3#3V;wH?k6;_np?Tqo$vtD zU@Ju0l!q<~QS6}aR@|U#3Cd{?xG4pL4*dukQoybDC1G|e^$@YvP>^<4fFI*|(gD#%9(kE|#bzF@Y;V2BK~M(=w*2^OlQv z)${G!f`uIhS+Y2QGk0e5Se@_ha99(VrNB|pW#|Uv}(>VIebJ9df-6B$d!fOq!@_lqNG1e)52%Bj9GSG!+ zT5IN4@{xi{Xq?Q?zp*kZx16@yD{k(N(iwwZC$_@oAH`#Z*f8XzTM)7<E)fE%h~4mnMAV=tWTUZlqd zTh}*K*S68epl1tQPC^_S(|>SX5_nXM4n;~&(ezSqb6XGWvwC#F=fy$k=-&7)H{Z(b zF~sDEAgs1t)+I>153Y@3$aVd52*|L)pJqNV05T8QDEo+Q!xpTUY}X%^8Fn=hN*u7h zcVuppOh!G{xA?p%S$973O-LWcFN9^xckDUeft=PlSVY%wO@${@z=y2c`}S24mFU0X zo4evUSoqs{I(Ryv)H|QIT0G1v=W@kezos{KOFF=uuI$MtHIZ<5`)#H~cyuKcX7!DI zau#f45vTO(7nxv9&_B~ug>JDaapDWw9{m*5EB-J#FPO+auoZmnlYQzi51K`g?GBZE z&0(t_8uK1fp!64nJQb)00EgK-L^J=%bi;nVKY+ZDC=m=x<6%g^ml20$%2Q{zO(Kh* zW%h6Fw2#B9Hr>R1Ag!ivti+A3?-IJH@I*2XIf=pq@b zirT8|$d=c(3Ifw;`zwZbp`4Q;mE4S#&(C0M5p3x*M{kkd@IgUteH6|cu{f9f%?{&+d&4M87;CrTpyfRjL@4*uQ5E`)sCA{WlFbV%#VwYy z1`F@pF%eqzDzQC*ObZ zSH}!<&~i>^cB)cyle?0~{7WU2b{i+uk4BlaDQ*nx44>pS=A;JUA(ISXu~_<4%Sfb& zouHmUF#2^r0HJ=EH47ib?f7b>5!^~FhRcn_k5+Wxa6kE=u`v&pTIq86y^mm7^v z%Z+E7T6#ZR`f@EbIXowVNz7UV{ZM0_u1c2Cast)(z;o~SFXiCB;>460ItoeYwu%K_pz(=u8Et4<|RK?T|R`d(;|gUF2`Eq1_IX>sSPbtdKKq_fmO6BHC5xG z!Ax`0rNOGl$aL95SSql^UIoqOmP$+@eN=Ix8f`(E+Fc)urqdoJFg4zM5#{mGVr3u? zt}u2YH<@t(LPl1lj%^e3e_H#EP!WSv5_h{Ix4B<>U-nklaS{@bF_g?wFj>=C5#p%( zlwkLqW<1OU#~6k!Bs1^qOJSZ_A&ZG}M*a;lLr7LSi9phcG#8lrRLPM=$3rGg@L64* zR=QWiub#&C3PJSM5lWsdTyK+Mc*NZb!}c-IF06cuoW;ky4D&Z{;T zKRCzCpWA}@7|2&M@n~g7EJh2vXuX+zhBqzt&8y~`z@`4v6m_9EHJNgbXZ>wlz^)l~ zG5lgzn)ea$4;7LRD{{85?N&hrN=a=gk#P)u$ei37O}{$5a9Zm3(z1WUw9K~U#!X{V z%#Nx4y8@a`KA>-`8@W!}yXJB(@pUolEIL*y&?z(YV=Htvm@d>%y2yV(U8dla_GbfI zvg|lAk-y>qz(c!-Cz~R4_xEqAHFzNhK~iE0P{G0{K0tJD&IE^-P$KHZrMzNMZ)ucg%|)!Rp-#_Ihe=Ct*X@tG1gAwP>%zGwrpr>&1rIMmq3ug}#C%B1bDx+JH#!y;mD2mlXVYQau2A`I-7aVc zzfiz(;tk_(p&tNZr>OEn5a=02&qu-%23OA&l-rQ42PBP$-}nGV%P{-{`?XD#gwr>r zjG*y2! zPi_wTM+Os9>R1w$wNSEp%z6i=AJCv-{PvW4e~${wJ@__sw!8@W(Hb7+a}u^0^ZCD( z?`k6U6uv=^kC`W~ICV!F)$oU+nlBUbUqAS^ zs+j$qAh}u}bFOkBm{|r~mL&MV`bb*IW2C`~GF&U9!>DjN2=SNVZtd3R1%7)rh*699 z>VC-P$_rc~_L28r15 zu6~}sW$mQSmN5E8;1bMFL9?e)J-UdZ??3bUlg8|sI{6e%cSN-&E(8x&0tPDsv^~@v zBdI@=P^S2LzDM1)>;LRYkh#A*Dq+9syaML0JxCH*N6_esxjo>EkM)-ht%y%W*UnyI zciq=SX!vigvK|!-iz54UNyjdLr$~=GLB!=BhvEqMsU8OVcX*7X@jZ=z&O??DLN1sJ z)74Dgh#g5roQ_-7H@Q&FvTKFa#_7RnxZ{9^jtWj1<;J+*aoUCs5d}Z>-!vytW^1Wn z)EieUDu^jdBO;D5(b`LS!C=rMmnT@9lIj5$7-d|X=1(&#T7#=Y+q9t2>27%4L}+r9W5Yw6Z_}D z;S@mp0v;GW2>tVLE<^mj=R(RC1ZXTsrtBE{W(ONd4)ilzop9e@7UQlzC`XUgiYvJfTxU;sZSTk>gb%Rij8A_4dddsAXVecA zPRsVeUS_5KP{V2G!Tl42!I&^gbIh1CCElAF!G zLk=F(qAf!}5}Oujk}}o#3!Ri*U3Ugrj_(9_t}-MJ>_~tENdo3o?H44T!_RR@oo299 z7M|?P)z@Ej#r8&|`een&CpHFea(6TW3LW?sz&f>>RbShJ8T)Dh41(^5!f^rt)Ve88 zv2yHaV{K#N`-Sn>So=eE-oNBMupd*$?-vErQ6ydS3FPS~yBQTb6ys(VS&LODboH!gM%5?wOA5|R}z$1WZ(&d#WV5~+0^@p_AFZPH9z(Nlu zH2(Ca!MJ{1zayQ|SZ8)GB{Zs%lnOZ3(vOxUJT{gBy(6JwSg-)Xi|)6$%(;Z!yih(3 z7gBBjwxs&Rl?ir1sjVHy7ZB2`+>>#J@C*|8qj!NyYx&!4KO|c^17Lw!Y`6BY1o^u; z>_9}?>h%3T@323bdBIux?4_&Mc)dahpo(g+uh$RYRr3=N%q`u!0z!#0ToGn?*Z)Zm2|=O&asaznj9Fx%LznIA8r1*kr@9^vBEewvr{->?(GTjog8&k zUJU7oV78cRz&UnVa2V2nI1fgoXg+=H;ZOADt5f$+E-4C2!x9@p?GiJVIaRv0u8g2B zj0SVZ3=RcDs;#fvmpT-MbvA4v>c%1Tv?M!aTDGazeay;IQPIa+vu;Wuy^^&hq&87sE1mWuNbgB0K(E#1f~+ z_}|OQT;|0G2W`L$J_;_y`zZ{)fJci?zL4$SW&K{+xuYyiXV=)D)kMOtso?|Mrtk$0 zWj{szOwyNOWURF)LNij!Ev{})5tHpH{7d4CcMU9$&76#d)|%m$@?;5y(Sb+AvZ5t2 z+!U;a6&i*-JgUC@dHmfp^Ya8PPpCtXh6NE`pWFai{ieO$rtVP~yFM&sKu2YHcDu~K zV5scs{`P>P2eop?R4AXY2`Ta8osu22mZ|#?&zVJZnD}v!x`BEQ1CJe`P=eD_|WwshBa5OL*f3a(8H;UbRM-yrx}Rp;cR zV=VBjKMi-xdS)L&BEq3H;WX<~rs;f6e~!exEUUT^|^?(s|+6iW__oZ?6%KG!TQ^507z_lU^f{Xn~$W z3QkL;~v8$`K0fY^|{vJjKQfpjf0L_{u!IdV}|#EXP}HXD8ZGky@KO0`7+g`i#Iqo5*r zoC5reuUavOO2&UyZRl|W(U7*kvj|78nFire-+22#V%>;O7XQT5+BTic?Xy%Cg}ozs0BXZ3J2ZhvnVLDu|$5s2;MZ zwe_sP< zrqxwe`dv;X=w|sA$O>2F!t!CAN8EF2#n~j8Zq8M^;B$!?pVV;*-P+SxIu=1jNitqH zF>;+(BT!Vi{jj?UH9SpHO=RRl!}3BHAU|-Q^>hKgqA-!Fw^I27pip)RGv_K0o)CQE ztj7L39Lo2SGB9>&PlzB>KOFDEA~M0g5h||(;U-|pn?W5u?#O$hg6{>R{H1QV&grt7)$iBK+7e>uq3|vB+PDZe1Q}4^nD5O?9O~d(XCZ! znKdbBVQ%535ngtWiMfP81P+FL`Tsi)#<%lxRd~dh#ICi3#K`{~vMM%TuA(PBKm~e+ zI*Y0gI@mW&FBunee4vh%JeY}AbbN?CRBl1AhTaDSMq{4iUc`6Os`UyiWw5tw&&qkt zsnWn=J^Q>gjgr5%k7^Y`WdgCkevYaqy0h$72UvXU5M_|snG-g}URoUB6c}3zLfQbzZs6}sMc<6R6|Z;6UJTLRn#u#nrG!vFY`(b_XK$0`Y-BlD4a$d;kat=Y2WN~Lr+ zZt}X7@7i_$ILDWX!?Y+@)8BId0#vK#U7x}zF@q+GClox|eM^d7(nEW+D@+5@X;HOvn4QN!Uv(e`=|B!Fcv~~B%DKuTpayyX6d;J1y$&vx;$fHKMjY19*{gz& z0d#XFj@J|0+qr|?w1Hz_R}*yt_zKQb+qK^pixKLLRZgBc#(qrgHz6Wz?!fulH&jT@ zV1?Pyg(aVYVgqonCN3h8_-ZwURu=$D_C69nM@hB{;vk#`{!%2PWsU%9buCP*sjxWLDjWAGX%B0jDw|Qi+iY+*40iU>6r)G8qE>G zRnt=HHi@$QedAi}OlDZ5+fGHx>)1Yu!Xexb(CAk`4t3+!1cCyNmr4R1A|3G(I>$a0q2FPXtRnGQ)jKCRU?R+ud=S{sQ@Wwph$0 zUkKU72U^-W#w4ylIxPd?bKo_P9ogS#6Rz&Bd<*(CLBm=}MtHLLkiUu z`h!NA`GxJFV!b1fBz_%D&u%0i12v-Q*yS!!H}RLWz@9@Fdy%?AO@d?kw^ezswLur1mQ2K0P7zKNUI- z$&IT-({`pQTp)BlpKHqf&Y_s@cXNI-xP59YI^&iEHwIUeVV1yJ*_cmoLqVL?j5OPW zy6ZJd&U8`8LeE$gea8pMT*znr;>u$20;w;{iYJ=cv01i$iDVD45>?P1*xJzBL6W$2 zrPE^lVWItRpvG)G*&uk(+gETfgY zdOs?MBY|K>eI9Am`pitoN<@r?P5EB_evRER*cdRVYSS9LeP!e8FCSTS%KhK3jnPZI z5?}MT)-3=qr#Y66q^g~0gJ`|vOHkitzGrK?!km;azu}}ay7;BkIfxCp&oF?QPEM&R zQH!8n6;!RM-P%w1*={m)IxBSH_zW%>YMH!oSK=(Mp}j~&toSb>t%e@mo|DYmhskWK z$6^Mg{FlGiaaf!Ey|n>W`(7FSr=gM6`^@!F24GEb>v1ifzSz-m^f`K)c z{?BDRIVrXYvjb-_I>o(OokW;`=)CGE_^lNg~3C22liC zQ>r!9_jHqKJ4a5eE?nEPQcU*3ekae*YvsKl7{V$f`1ymzz`{599^8!ASbONr2B@$)-+!>i5tM}AGLm!*5VO}Z}+LpQDfBd+4WfihR$o!^v5Om%3dJ?aB(S_;r!r1Lk2mhxNuo z&q=t30G1s>)d-Jx5TPk5Brpj87KS0Ay-8l=XCq20-9q``{HtP6ALqHb&J0aWF_V0McG&=-D6$6hLJCPK~A_!8z~5;I*oo1*?0 ze`k@Gg5(5wgv7sN3cQC_&T_WS3CwuAvb)mkRvrV}z&83jVPk6hp zQj3(piMZ$&7=@-2${@F4IvJ**G~r2P@E^=%kQeVMRHzLVVLxP%k;7d-irVc=sw}slr^|}U<;s$ z@<~ux{*e$&#kG>A3~GF*^RV+=Fs}_zt&~xOA%ambq0De)_H)ia4gjTm#mTlNvlZz7 z?fL!a1R=9ApV&Sg0MEkTW3*Qt-qY2j8;xOx)aIAv3CbyPU`mk;5&kU*B^X1&TZg7r zma!J6KS?JX?F|{~T#GlKtj9-Vp{k({WKWGVO++kW?(qoX(QZ~N1LN7{=1I>yndRpx zTfh_vc({ zc3m7zS zG?+l$qS#H}HB{)PzftBA7WTja3hjMY=bd8!Kc?lP-MC(YoX=T62QkU#>>CeCRo<;( z?z-wc={3Ra?NE{QAtVt9)ZeXabVeVj1T~dK^^=(hM?B$-R{I^PAsRl%aA*l7Ca4~O zT9c53vAJP|#yjmpHG3A-#|vEgpkUGPj#qFoE>GLLDX<60xoFUVJ}lxj9G_ugQ78%$ zGKsKF>U4_b@Eo7te6AZx&Kf0nGXK^OLzmu$hXfcMq=1yTEuD z-hY)PM7yl`I&S-$u8sdVgkNpl%gq4DyKc94s+6_Y_FhPazk5l4Hb(cyXj>;PQzf1N_&7}UiiQKjaL;QlpIGr z8vs?BKYBGF|MFj^J6bNJc{z+1uPFS>Qt;cbhAj`ts&yE9mQr+=v_b8}NQhIJLGKpv z6Dp~fex)o{X_ZVLcL+X0FBKA5|1!h9;;-2vuK&_$z z1^@QO(YQ)nZT~sagM2P|^37Z*LAZdGlO8#37)g7V&eQVy@*=TEsZJvS`(Hb{JsRu< z1E&Z)2L+YpQ%}ES*~!c;h*EKEW#5@XMHbn_cxYQH3lr)7lhG2jiBrBo@$32R?QAQH zNMD|jH55Or4^qcsMESp=5cEf4%- zJoYdv{l9ymJ!>;0cYSFRtuN8o%}^aaIr7p?beX|Em#adDki4RB_313a?ZLIpCs+C& z7?P6nt26VO^eah7UcS5K@bZ1%iwq?R!zV(A2#5Wa)$s4J~q2{`>VrtcUyVq-PlrSSSmB+1xv)!e5%Z8 zEc&{`nSS1Hx6^wi6DbWB6K(ucE8gJ)I^*O0s^#gK!(0cLV{U4Of4hRtrbK=Bcpv}? zUUVx624tKqT9E?8?JhH=A@b1dEb=cL=L9~RB1@as-vyND``ZY(`7ztf&;THmr%i5+ z;c^zSG5pG*&VQ>pB1KEZI%841g?>JvLpD{)xI#k3bRO2kQD={g7L6#vh%{9Dq~<+0&PuU#b%HH22k#G6viVv0On%}mVNoN)j~+Xp2w;80NMLG-6I6y zxwyh41!rti|6WhisJ=X~B0G{*b~!gXn-s=10;eRV(A)ZHE@86K`&sjA%6zhf>kgE;sYGbYd;pQYmk%%a%ljOylI;z1^w$E_S9PW$A;rYFf#5|O+Q*od9TR{QJRMp z*A}u(xbUU#A}HGDyW(x9%~@s2Y-80Vo|VKqKXZ+N$6R|o7|=(WT)|g~y6{%xwx_&5 zwYIj94twJ8ppbb9G!-kYF_mM`u9#r)_&<>6;I$TIp=0q3j%9BdbcxiGy-67e@Cuiz zq@TV2eI5y0uWYFO#QQ7ln}*&k7AbNa5?2dI0L_T`oC5h5JrSHEWX%hwsxd9IMDR&< zVy`rlSnwecQ;(eB^u~(I3D-M*%j(}LT_x&@iD{}_O32l^Q3_Sx9^}pC&B=9KowB&^ zHGMBq%I`g*Btj1AG#liamD;y1TUF>21WQeSML6Vk6@M!R9$vz5_&pXwcoFkTfYtiA zQl&mOlw+ismVB@fI;m-amzrS<#o2zgtYbm!m7*i+$2-7EDV9dyTqU$!zHbhz%NWoe)rW1 z``hQw-+5M#{r)G${v)Y({|CZtp*6SPlmdjfMImza!QKTDu32T^PbgpVkC%kPj!FG)wt`BLGuD)1^1AU zCB?)iG+Hkq#J`%?6e~XQQUX6dkW+oqxLsMm*1)+*Q%pfD#ye##2hh^S7M%$rl2--1 zy{7F$){b_v-yFozH17M7v&9y7T!D`p43X0u!I<O zp%@c%F0$ZgGb))+mCi0$aK`?;(5~m_Zn8=P`A1%+k*$O*8u;hEjcT45d%I^)A=s-q zEIu*9$+qiiX;a?GiJAe{1}?IEXr+@0aidhg(kbW6t z`cKeH{bRBr=55x6#)Hbi{TH9H@U!FTmg^vb(m?v4))p<&ct>g@(gh9v6h zyKd|NbrChDh0q*hkV#%pWj#zhwM6C=DGmznzLCN0$T-W_2UGbhDEn&Zh!)u>N1Ph| zU{V-CdCK{QQxJP!frfvziQSCj;N$~AyQRKWF-lxvF|K+v+S63PH*P9dbCgO$@xpff z3^Xc7`QEk^vp+84V0}#>SHm)JvBbtG=OA28q6<<~Ig5)}qVjj&FlR55lr7XsP|waT z_&8-0vsL?iDH{#{U?{^aRxjt!TeO?*U9I>2NQ#dyd1TY**3P3O<*RW>9&}BZi(Xdx zA@A4X`+ZRY-JeFjF9fHt^O4@pT5doEXU1p^gdUMLm%xgK(gzRb=*b8%eAZ@ z{b=n^6i;;Xii6f}=i$LxtFQ_8ocLJO%c4&-IPu)5ttYMn`AU_WO?f%l5eM^x#dwc0 zt`V`KcwKS@;?B=JU8k7Kyf-b$&yp{D{d5fJaKq`J_c?53*7@^{-gX&7*emRpI+te|>IL9x$L>HLz6)D4szHp3E5x?;X zYUjkFr(|3({Pc#IB8FVWV|jnm4ag!MvxD^(wIAY&2iiR#S>C`&HjDD0&XQ8c(l{Dn zAE<%zQo{nSvLYr@5=xzu_5gJ-05Jub2QuJdWd?mr@H`&7RDQ<}<$^*Yx3RYwWC9ez z`ki&sI@&dAKq{a1w$d3T`4nJm#bV#&$2WZDdhL%mo3dEq9y3DsNgzT9sk(g(hGOuq zXZGa?*sN2txWa&l3nmB_2sUL+ijiE~Qjg1Q8Ctb=+6W?*b8 zVxP_hb;DA;M+S;uPz0&P3WRZ^C76=oeAV%wQiM7la5*V_&T(SMNRrCr@!)6vLNEI{ zkF67teouk_xG!k9*t(R@q^GR4;Ya2NYgjKEQo>0hyIQte*tn71SG$XSu-%+3>kF zFDbOGu_MpeZ}L)&zj6ofPjY`7 zK|5cEN-E0K2)p-qCdm-%+kch5R#GaXHz3v%BA0O(*<$%@JCi9B*Kk{~5(mJ(xkJ&S z0VmjT0!djuenLMg6fS2;jGCUCeu)kZ+WaqLWipz_#s(+&B0J+?`lvL~jb&9*x9!R~ zT*-`EFE!0(4q1D$)YCHy0lr80dMrlRGiT17WT`YL8jMwJF|>alZY)jlhof}wHEukj zN4X&b@)?d$ZdUnBVv(0m=a0>Lv?|I(Y+h~Wcz^u1b_2D(Ow3RKdwGbeGm`kzS*gF$~KJaqFmQNk6NRXr+0f&kA$4Vey3jQTtU00co`MyUJ z+J6-r;goFBk_+zzHG^?CX>e>?f)twd6XL=b2ua}Nqi**5QWueg#(X8W@~hHIhvSP0 z_=ll*z)I1Y8ruad(iG}kkPHAt z)?uK6>t5RLHG|A#4Gag?9d^jV?#qp_)~*yy3}(Ly$g7zKZ#u_+;@V}-`3i! zm)%(|%2{N`ZD6y0vty6rP}bBjj+Z@;`K)Z)M8g~ed3A3SmgbmfD(bI-sctc>iRm_~ zpq;Z>+b>4fTL)+gBk2$wGlx{*gxsT{=hD+Z-505(5pHZma92Sl_>-DjRpF6wxicSx zC@kqqG$-&2YK`@+DR><{^JXRrVod`YnR^bIe>6I1BUmS{ggg8KnGHC&0z^Zq@B*95 zVN9!GEBGY$I|-#UNH5uYAmUg$y|+z#ukGhrRz8P5=Jzp=V@L?=neHVw<}5s2u5k8} zoe!QIrXJ}jgL#W4$Jg~miJ{)_3%|$OWbZ`Xf+J(ww#E>KBx%56+~$cOTkehf4PqVU zyaf$s?aqD~|lk@wF>e|;72i5bKZnHWJlSNlI%w(_(% zwl%?A-onIl3gHBO5KnNAqJw)jXbG}n0}N9JXeZbN)4Poix`-KM2MDuRx@pKqdQ>7` zz7iLWdyxVjb~iX2D#j8^q@(!tmd{zc>5f%!>#BfeCKQ4NYM)1Mt{MpZNj--T&m}#W zmaQNo*s`y0j!!RlDf&g+8h2Q9%MJo*9yI$0)&sVtfOg19)A4Eg!4&Ap|Pl@Z1fH&BOD_cI0Z&<1+E``17X15qc7!!T7Nj`B_T z=H$U&FP`DGGHSge{OTa;*KnC!vspMje&+dj>K^#d{UOKF$jE_mvFez39u)B`OiET_ z5wrV1#XB!9Y5*+M-QAd5Vt7puw=aSY>R2TQ`Uz3w+EUCplkH#ivKjfq70(>D9Ze)hS!q;27*OJ zV*j$p%Be7Me~HmJ?nOsj6a#mOpFvaagr|W~(?0)9>Zq?jd$FvJ<~*acj3=ChAOIrB zU8w>h?#lo_C;;dKQGnBmm955G0jvf>9B?c>8}wm7ez2r9sgv5Dk1#T|JUh2olxu2q z90B%5kFbWA-R`%%lpLY#IYum?lJxGoH+S()WkywDJK;~}cf2V_)mk4-vJ;t$`aDT#VX5faNwyG-|10m&H=>NlSsMapX5w(4vjsA>+7KZ)=+iO0= z-^5Ao27mn>1&k&_MdQ{4?PIl{bLpTyh%qSkGkQ}KR-ZhYNwWfhaPJEj-EO1Cz^))* z`Xu$f*}X!Wyb)C4#w=FQ#6KBdun>g{>xb=wked!Q&3)L!6Dw?s-An*@9g|2%qI!j) zG=AM5zInaTe+K}P`M*D-oP0TnRIM2K63d1kJNQ6Iz8{50O#V+>vYN32zlW8M>(lP8 zY@??rtC@tUhPD2M!Sra8hoSKkKee!=Vbku(y$@=0o``N~fFKCp7o5*Sp;SLr5Q{xL zOtd~;X=@^{Am!R6fMRJ(FOFa3k6rt%4rPZ4-!HoJY3DK(&W?DA2``#)OcLgfxnS#yVj z75WgRkN6^jm(}<;kzPE{2p>c_Igi*5HNdggIY!tsqu?|kt0BeI1XiYgNgK4qo4r2@=&&T{cc**93W)0*_nh0-aM@1Xxvn3U^|&&mrM zT)k%JKGM`v&X>*BmX4v`15nCyD*VVMvk^#K?74nA$$;p8HS4grvsk!>3XT{B`MkwM z_DJioc~*aw%xp|Q`h7Zn%mIzC`23Y+wUyHiDp%%f_duq0lqhTj)M29M@OEGnwZ|rN zDhxwPn7s_&jkT4%J^qE3fyI8ZS>s&}MGW94-C3pA6_0Nb;({_vy>EVIx7t3b;qs8! zwV!w=e>|AQUN`ZmJE}3ejf20#dg-xmwIW!mkebuL-dOSVVfd?CO#Ye|%Buhw%knN7 z17{+isXxCTdG>ITFUR?AsltWx4mkRD8dU|_A;Fp(h3p3d42Od>KgHOakdJ%jM?Dv^ zsU-4d^E9zhuLlMbNGY+;+ad`rN+=bp7LLJ>{+{XNEaJ6Je?9!?pv4IlM@?io@O}tW zbBlNZwu$`b$~gz7wZ3P!L%q=!kzCHc+~?hJmqKgY&hoKWE&|51_u7$s5~08hex?(d%Car#n4qmf zf%!I|#4ivj9>fhk;V-at0>p9p=JEmTd&>xMk<=aX?rZiQ2Jtf*Q{z2PYmz&G2815? zLK>Qt1*7zoqpA0cad?{aEt~Sq&S8z{X9@6jE|suTswc%qEZm_}aX?(*R4l z&y`EGm>j&(>*bb^EfT*X64fs^W;YzNdh^*ZoMk3`P;*N%7Y?AQk-E$}3ARy7?Ohmp zRpN}Ep34+GsN#39J45{Ve>;tylfyw=X8|_ucg6)!Zd~SsB~$9 zs@lmyh0hl{$8&+;YG&|#;|GiC8FJRkAMF-ItN-k?T~f5o``^o-la;XEwJIeIS2ih zI-c4{$?K~&E3^3Uf3;wNIrDh_@7y5tUEVZydkTzjj>HKryy;as3B!nA%1!eN8V~4f zTJ0gzSTRTfwL(ff7;nIu#ahy4=litOoQ&akhE`QP`f3Hi=v!wF2Sr&V@0B~<#n}rJ z^}+BF5MCS=oIGH|qz60#D$GF3`i^DeS6hsVvwW=~jGoE}>OUg!7PvFQVo>k-lnDyW}0$X-Z~Hl4Fi zkf>Q#rGJITP!NQ@v@+-%>Uf3_Zf76WLpc;e`uiDIke1>Yzh)=Nteuipo~1qmkNJzA zbiB^J)v5p`4mq=+VP?1|u-<-?%F`EA6k2v3>Ha*W`gnYBB$uY_cU`rBOV6r;5n@7% zv-%l-Vm~aIuJVq=E$&Qxv&{kM%nZn5-?*6-9Gjk9TJoRCk~;fftJzOtrdJB@n~wrJ z==FCP-DJ$4c?5&O)*g;gp%qerR;KAA`ARuMr6ww#+V3F$HjxNRnZFmpzVAECnHEDN z-JqI-dw<(`z8(;aUfWs4n`LoEyKZG7aa+1x8oGx>R3}kGg_5m@SkX}oEUWNpoq#v4 zq)ttx(QnSpK$8U51M_Ic?C$JLeClFf2+BBgR@?!J{50~_~CNpX+AvyH?fKYa0!RtYwcM`*x>Z9#TF4kudu zee^MGfv=-7hhX|dQDs@c)r$gjfzsbbv|yD~MoFN)*H&FwF>|!S=^BDJKR+t(>H0~S z)7mWp{tli6m{d=rF&`_7GtsBfnf0=+%EyuCtcWUhU1*VlgWAd{XV(YZlo?JN^R>Nl? zD>!*EaBuS{>^jXA7=IHlRXTmTNbUFcHz%XPDh82k1fNR;Fn~4R*E@m2zZGUfnH@qN z=Wi|wD@;58$NInGEnx;|jrENj?5gP)uWvBvF)rBW(@EliZ}`=$?wX8$4hb)TM7PmM zJAa3GI&#|kFpvtD&)+0PhnpJL$HkQa6{NKbjyT@e0OR{n$Wx?`W9^@>Z$Pa-r}Gtu z14Tgi2;t4L9L>L?-~%=szh0L9cwB;-&MaUC=(@pK>07}r(fcYqKilR49IFJ6>;F6r z0xJz^2n-&{c*h<(5iZ#PeO$hJEDkp%!Z&)Ol+iQwG5*daVj*{x#iaezlpY^C5wgQ(7#EA+z2xyP3z_RC!unaN5MQ@$^*oo3AQfN`1yLw9NlU8g-bmCY~bSoayS2ijU{$`5_no`jUvQyk+h1{-0_ z!D#(437_i(a#oI#ev1q$Q7jzyyZNB$Q><`Jwt7~v_>)-&>EUQ#Ru&UfNSBiChmm?p zRI?L5p24l+AmWIB?8y@pbJ+@SyK@ep7v*Xh`69f<|?O`6zdR1#)VG>=cr9PPcUXqavJC@J^@TzCoscO|>h&57ANJyLA zJjHtI6kIz11R`8HAFmjoDYg_QmYHuHIxl=RMDD~GE8`F)Ex5p^*&~A71g5*uM!X53q(j=rb z_Ted7C-Y@gGE}AkhlMRinv=1lwM7`}YsOIh!XP^WE~+#~aM=yt3EDzD4uZygZA?hk z0CAbSby)H|s$*kIPmUz}{so*aQ);ik^;ANH;pDNt7wq)BSiMI3N$0X-7rtY*ziuIB z^5(5)Ivrg?y({=!p-sEy)&7TmF6=*F_jMMbSR9-n554NZl~p)jCE9vOP^zx+GAnc; zH8g046giFqrYRNMLIy;`6X%;*czG?qybb#y@3$Fbt~luXkPY_Tb{M&#q%wG270+7{ zBUVtlUZEU8*L^PYgBY7LvPy2s`zpw6;2s}%#Cw0l!CJ(%EVDX-Y%jlO!>-Kt$5Nbi z7YbAbd!BgPFD3hjFRBPYje2X*Nx-f>Wos)!TL1%Pr%F(>W6|)dB;ym%4+{{iW$3W1 zghUpS@kcMhGn;b)V{0;$p_AUdoKr}&8FD2XZqNzI(Cn^dN{GI66Q=Q_bSf%3+m7kR7=PxH7*XpeMhK<;9syA@T<|0#JM zjAXHQPJ1yP@IsXJ))*ldbkE%9hWVuG+!`?5hGM7kTPnI0D*U8KJAg<9SsXBsMSR4J zE&`!u=~0r`mVQ#9e*6qxnQx*<@shUn@z=SU-+>9z zW@FHsp;L`@GG5jNUYB&|#XVSK0*+ZeXS^)=5qOL-+q)Gz;cyX(VjXZD+qa*qfZ>kq zA?KDl3~0m4ySizhaRmYtD;*%D;{WN_E(IzJ$t2*9nW-~@mEagg0p(QB|5e4TKFdiO zbD?CXrhx`wV54xsQ`ENYjyu=u%S^0FEDwFPOerz?rgSf};m7aoV>g{Of)z3uM;Adj z>m;l{Y5HAu+)C8~QpN);R9A7{Zm(N9jzu9ji_=_joXG=h>su0x|B0Pr13?)4K7h9l zL=|3|8wlmw9zIX(H~%ma2HpROd46R^$EqUf_)egli-^k$GU@qTosd1$zKn-Rb3OQ<_VFe53r49_txYjwlahj$Z6zd zVW@Z-P~CEl(rs#c93T7eA@PNEdGk!EW3W)Z@PQynAjUgzv*PxDyM}I?0O42TjliGr z))66{YNG+xLAh}A3}Pzwl^wJQXJ0$Mie91(h6^W(agd^9Wt62X!CZ&N4q6ZX?U~?i zeT|?-=)INNzW)SWV!#y3N3AI@0Z@_i#8#yqDK20!8Sj=Gy;|(&N2qoRymUJ0onJfq z)`9H%88$FWvbWZ7`#xG#2Qkx>z0$!;7=g1ny#=NOD*SyP^jzKH`iDV?rg z_r~SIX0cQiiEisa72=qs@S>D^;rx_HzNFJ4STZ(AW}Dn0b#B;X?cZJ!v4Eisf3b!V z9{S;i8ADy1EXVa5sC;ul&!1ld!mF5a!3k= zr;XL+xcD8?s?G`MG=w1Q*b(;Fa6>QN#(g^}I?NwFczgp~^DMzz)fOl41DEjd|5bjO zChf!bv)zXxBpb<#L@DjO*#+`O9YGU}Fz&YLUB^&qSBJ7#`r;Y2gnc)@aaQ(EXR-1; zPw@3N8SXfg2|qZ)t(UnfsNv!A_J{G5E*AMAZG81HohJL~#Y83x%n{dVvjRN^FL6VV z5Q^u>G~7%ytjN>?P7gx`Tc#th>iJgqjMJYgH7+RS%+&G#bmf@$&?qSNuh|_)dLMt_ zITe05(D8MMoT#^^ZXcq+$02M$F@|_}nos#Nups0CGzi6##)Ej%a{wz#4HG7$$WyYb zI>k0~oQgI$=Y5fHhz{z|=y#G;=+>1eKTUh0VyZhK#}n(qHs|dh#KRNJh<}fdJ0AMB zMz*$+Nd_th$C!JB1hMc9O*9|?0000AsT9Qu`a4)q0O$b4SP8pF^>MA#M5zrKw!bSR zp~G@l38xO+jOIF#uXS>9=E3_oTkP0pT7|I5-{yp$AR=nmm8B_Zx@W{}%wfmTH>I!V4O5Nu};}cTs~M6D$(!oM$F$-S46PY;fU+yq9^cy15aw9S21C zy$|2ol8&%KhrN@-%9Mr-_u9a z)miDeev4su8Ck_*{oJ2jLxVhJ0#HU+-l{iO4HW&^eBvBLR&Eg=sYoXJij7exwhVn{#1@8y_R3|8|2R1oDRC4_LSf15@M`8f zUbLjwp`owGk@GebsL~*9nLJ-XQB?QSfwgf+abq;D^UyqqqH>YT$lhK`nsj=D5CFfi zt&~h^B#?Ga+j~wANX9)If~;(~&>=>$liwwea4VTXcM(wj6OPu5)2NU)|r=i^7Z|-5-Pxpu2Hv)^p*YQ!n1Nl9XJ9+-(E}%4y}SgH@F30 z8XHQ&*W?nD)$-lg{x;Q+32>3x31HS?Qs1T-Y%r`&B-t~zvtsQ$&l5rAjr)>b$UBWo zgtRbRMv6^Bn~fgtTLn2V%o2EZsU#7s;3);tF-FEN=uz!fa3iwxz}HMA$IV{}2PnZA zNQv_(9*H_M2M)tZqooTjRRD}xU`ST8G*FULnZaRT)J5Nh;P0o8>f9-rtn$z~wO$Mx zwuUj=$!U?F=()gd{hIf)jc^g7=xN6+rF58NsuV+r>UHv1zke3u0iqEdwgz=FSpNKX zNd=!ds+iYd8L1V6s5Rp>fT4@q>vVM5eru4Pb=PMc!SwW-YmsI$+4KQYx;3y&U0N!? zaej&j7SBc|GYIb9W@nID8aTu>y^VJ~`RXpipI3p6zS%-xtYh9->>;@kZ7VT!sLthr9z120);YQOP|Tzqavu3ryGXL!lZmgT>&Cn7KHauMx>)_HCl)b``u`f29hh5S50NFH(LqM}n2QIM&xNgk2H?-39eDUlgvl9xHlLUtmL|mrR&Pqe zx~MYR=6=4-s$L^&S#fQIQ9Z%8xz6Hg*@ZK=b*@bF0#sbLXcp+>Tpy}+@){ys+m!JP zAl%4_6F#wQ<=RBjYyQ2qoy?8qzA>2GLND5*fuw4bFfhV#ln*0?U z!PNZ0Mp4^i?Whi@daCiz;gMS<67%UoYC@&wnl9Jp%7q?k}d8LZxqpROR>=u&Uar+GHa-ov86F?#z$wuZ<-<7HzHU-d>n(mXT78^En>k9^R(n&G>hR6W z=?)UIwaf7Ic=SPbb6jG{8Mh$f;WvW-@os-vU{=sBIK@*FHw)b@a|-84g7%B6iLkPNGPFEH zr1RSdZhH8xjMLG?oRA39@hti93PnD97$BjB3sDfLYt3%3-VXntC@F+nu0-pj8Uql$3OnamOsq@%T~&d z?iNRZD^@?ZV-u-8nlZ#v0ND((W0EBE+AdOvj2GRmHF~!37SUM@tA{>9qe*42YS#pX2|{=8>N=JT?l(Xm=68IPjFzAx<5uAf-Z+FI|v1q;5O^Lu7 zw8>1+Hi;h;FI@YUbssYZ4O|`ryx`Pn4PDg1%II zcd3pAP4Xsvk5ybegC;O*aygNnaZq~B7y^ed;A{BhVSYHtGA08gR7J3FBEe`t;o|}p zm-4Q=}ntDUJS`OlSCp;^o-1kHEXcN}*3 zT8}E5H8&3XUMu=BpUs+i4XYr^=dZRD_F7u>g7ySb@?W9IDV+8neA!;ku(Q4Rf2wHW@CgC zP8GC}Q*_jVgN$b`BDqz+pT_yMD6A&IzcKskbA?#>$|>x9@0T zW)wEb1&V??5M9!{kwwL)qPb{cPEY@MdloWCUVSN5?*HIgZ{}`9ZOODRuVs7-{!6E= zJe4?a1t5#HUMz&TR?YI{=r=wKbQF=tRdh&YJN9c-0U8xON1X+d-a2jTtYkfky#*vg zKs(<(6B8`EFMNVHr&`(Bi*sSdeR$&d^)mjrKXrz$fKO;>5=3Sh&uJ=wpv0SvlR^+= zla6%f-A!m}kDSkJ@#9`|wa|mWqMzmyDxa;)hqySG(kn@M+yiD zv=2(9x3WwS$3tEs^AnbqQKUqHi8mW2ggOw!7K_9z#1rq6)+d<4kG^u?z6Q`TI6;6b z@vvhwjbdJqvZDnA>Om!w?9jIboCO4%pL!5IJ)w^NUi%6C35k{fL(MaB1StqpEqKD% z<7odP_GRsZ`P0Yc3X;>U!e8(6^T$IL{VHpR*@^ z>+ttd(QbStWaf4QfFfw@L{=(>Z%?1)40hO_KM4BH+MQ0jyvb0eKWRDc!}_@No$f)_{2 zj1WG2Ccv*@(Tn{Ytk33p#v0GB2w?QK;4p-nW!QqYFTP_fQHMGba`=BW^8ASyJNq8w zKSyZK!>?0uFdk1o1Lb^?EjJD1u#b?f0#B-C>89(_dWnX^&GJYl(LCTfd8(VeLEY)V?Dq8t(ieV#gD+YUQmT_c6LYlKAzdb6tM(G&#%b8gmd2v7 zC@y3%Ahaa$fGd2=nWV$>V&M-%?bTJ);)`FzAlmh&@W=%`Jl??XvjD1kgsn=h)oy;i zP*K45H`HuKjEi@OVb7FeEjxYtSFNW#IRT6OhH&NI_0^7S0eV=6X_$tWkM?LDR42*F zs~bQ)d)b}wHq+*;yWg4~o~x-XJ_76x-$N4(E8Z*2Q&k%Fx?>s-X#ygjj693xRZn<- zYi(^H9Qb!Pk~|g3N3(4_7_g?$h9(Nn&*EuEJC?x~)++b%%(TQSr--5D4U~Vfjd0Zj zOsjcr2F=9qGXv9}ToKUFXPWmL8R}{xgrxm+`z0>|uHqsBR`+?5BRA@^RzyhE&C)}y zs!Q~DdR`H*&n>e=^sXW4YanFnYDHs$Pm!w{A!MvBpqMCQxaE}rt}=OptlyP?kFcWq z(IK9Kb*Z&DO&0m|jdoV$eSljbP2bn+YQ{7k$I$7$Phy&0$GEBTV{#d7)$oT{Wm8Up zuzK`Ef;t+f`U#v1Iwhwsat+#jT~nnud-sup<~Ip`fOve)+gsFp3gf)OasAiy8S$hJ z6!2nn`Io!{A#Hd${)Pm5mKYN-s>|pDS7gwAX|iela$W?96QtX*!a{fz=F^N&g z`r+4mX;H(Z_1`xFgRD`Z#)H~gYeU#(Ru!a2OkJ{t}tnObVtS4P^x7*KCB^7j!C9qEAZ_>;%*=wqp-zr@jW31xdX@+B{# zfE}|H1#0xp3G^1bqB%)tR2d(_Cup*;?TIN~*QO_{e?b*-F#sLSL~`e^8q(npDIIqa u&;1n@64O%QBHN39F@nlm!_K(8xs+N@yfm~s4;p(%NhJ%^xp?1>0000KG7H!M literal 0 HcmV?d00001 diff --git a/frontend/src/assets/logo-24.svg b/frontend/src/assets/logo-24.svg new file mode 100644 index 000000000..dcaa04ce2 --- /dev/null +++ b/frontend/src/assets/logo-24.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/logo-64.svg b/frontend/src/assets/logo-64.svg new file mode 100644 index 000000000..add201161 --- /dev/null +++ b/frontend/src/assets/logo-64.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/moon-icon.svg b/frontend/src/assets/moon-icon.svg new file mode 100644 index 000000000..00854703d --- /dev/null +++ b/frontend/src/assets/moon-icon.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/output-placeholder.svg b/frontend/src/assets/output-placeholder.svg new file mode 100644 index 000000000..2567ee40d --- /dev/null +++ b/frontend/src/assets/output-placeholder.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/platform-settings.svg b/frontend/src/assets/platform-settings.svg new file mode 100644 index 000000000..92d051493 --- /dev/null +++ b/frontend/src/assets/platform-settings.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/steps.svg b/frontend/src/assets/steps.svg new file mode 100644 index 000000000..5e8229c2a --- /dev/null +++ b/frontend/src/assets/steps.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/sun-icon.svg b/frontend/src/assets/sun-icon.svg new file mode 100644 index 000000000..834613312 --- /dev/null +++ b/frontend/src/assets/sun-icon.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/src/assets/swatch.svg b/frontend/src/assets/swatch.svg new file mode 100644 index 000000000..2c7a0d207 --- /dev/null +++ b/frontend/src/assets/swatch.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/task.svg b/frontend/src/assets/task.svg new file mode 100644 index 000000000..9d651a263 --- /dev/null +++ b/frontend/src/assets/task.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/tool-ide-input-document-placeholder.svg b/frontend/src/assets/tool-ide-input-document-placeholder.svg new file mode 100644 index 000000000..fc76cc7a7 --- /dev/null +++ b/frontend/src/assets/tool-ide-input-document-placeholder.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/tool-ide-prompts-placeholder.svg b/frontend/src/assets/tool-ide-prompts-placeholder.svg new file mode 100644 index 000000000..4adcd25ab --- /dev/null +++ b/frontend/src/assets/tool-ide-prompts-placeholder.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/tool.svg b/frontend/src/assets/tool.svg new file mode 100644 index 000000000..95d4e4719 --- /dev/null +++ b/frontend/src/assets/tool.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/vector-db.svg b/frontend/src/assets/vector-db.svg new file mode 100644 index 000000000..62d1f84b3 --- /dev/null +++ b/frontend/src/assets/vector-db.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/components/agency/actions/Actions.css b/frontend/src/components/agency/actions/Actions.css new file mode 100644 index 000000000..a6b504992 --- /dev/null +++ b/frontend/src/components/agency/actions/Actions.css @@ -0,0 +1,21 @@ +/* Styles for Actions */ + +.actions-container { + display: flex; + justify-content: space-between; + /* Space between the buttons and the status bar */ + align-items: center; + /* Vertically center align the status bar */ +} + +.status-bar { + flex-grow: 1; + /* Allow the status bar to expand and fill the available space */ + text-align: right; + /* Align text to the right within the status bar */ +} + +.step-icon { + opacity: 0.60; + image-rendering: pixelated; +} \ No newline at end of file diff --git a/frontend/src/components/agency/actions/Actions.jsx b/frontend/src/components/agency/actions/Actions.jsx new file mode 100644 index 000000000..98f89141f --- /dev/null +++ b/frontend/src/components/agency/actions/Actions.jsx @@ -0,0 +1,428 @@ +import { + ApiOutlined, + ClearOutlined, + DeploymentUnitOutlined, + FastForwardOutlined, + HistoryOutlined, + PlayCircleOutlined, + StepForwardOutlined, + StopOutlined, +} from "@ant-design/icons"; +import { Button, Divider, Space, Tooltip, Typography } from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import { StepIcon } from "../../../assets/index.js"; +import { wfExecutionTypes } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useSessionStore } from "../../../store/session-store"; +import { useWorkflowStore } from "../../../store/workflow-store"; +import { CreateApiDeploymentModal } from "../../deployments/create-api-deployment-modal/CreateApiDeploymentModal.jsx"; +import { SocketMessages } from "../../helpers/socket-messages/SocketMessages"; +import FileUpload from "../file-upload/FileUpload.jsx"; +import "./Actions.css"; + +function Actions({ statusBarMsg, initializeWfComp, stepLoader }) { + const [logId, setLogId] = useState(""); + const [executionId, setExecutionId] = useState(""); + const [execType, setExecType] = useState(""); + const [stepExecType, setStepExecType] = useState(""); + const [openFileUploadModal, setOpenFileUploadModal] = useState(false); + const [fileList, setFileList] = useState([]); + const [wfExecutionParams, setWfExecutionParams] = useState([]); + const [openAddApiModal, setOpenAddApiModal] = useState(false); + const [apiOpsPresent, setApiOpsPresent] = useState(false); + + const { details, isLoading, loadingType, updateWorkflow, source } = + useWorkflowStore(); + const { setAlertDetails } = useAlertStore(); + const { sessionDetails } = useSessionStore(); + + const axiosPrivate = useAxiosPrivate(); + + useEffect(() => { + setApiOpsPresent(source?.connection_type === "API"); + }, [source]); + + useEffect(() => { + if (stepExecType === wfExecutionTypes[1]) { + setStepExecType(""); + } + }, [stepLoader]); + + const getInputFile = (isInitial, isStepExecution, executionAction) => { + setWfExecutionParams([isInitial, isStepExecution, executionAction]); + setFileList([]); + setOpenFileUploadModal(true); + }; + + const handleInitialExecution = async ( + body, + isStepExecution, + executionAction + ) => { + initializeWfComp(); + if (isStepExecution) { + setExecType("STEP"); + body["execution_action"] = wfExecutionTypes[0]; + } else { + setExecType("NORMAL"); + } + + const loadingStatus = { + isLoading: true, + loadingType: "EXECUTE", + }; + updateWorkflow(loadingStatus); + + try { + const initialRes = await handleWfExecutionApi(body); + const execIdValue = initialRes?.data?.execution_id; + const logIdValue = initialRes?.data?.log_id; + + setExecutionId(execIdValue); + setLogId(logIdValue); + body["execution_id"] = execIdValue; + if (isStepExecution) { + body["execution_action"] = wfExecutionTypes[executionAction]; + } + const wfExecRes = await handleWfExecutionApi(body); + const data = wfExecRes?.data; + if (data?.execution_status === "ERROR") { + setAlertDetails({ + type: "error", + content: data?.error, + }); + } + } catch (err) { + const errorDetail = + err?.response?.data?.errors?.length > 0 + ? err.response.data.errors[0].detail + : "Something went wrong"; + setAlertDetails({ + type: "error", + content: errorDetail, + }); + } finally { + handleClearStates(); + loadingStatus["isLoading"] = false; + loadingStatus["loadingType"] = ""; + updateWorkflow(loadingStatus); + } + }; + + const handleWfExecution = async ( + isInitial, + isStepExecution, + executionAction + ) => { + const workflowId = details?.id; + + if (!workflowId) { + setAlertDetails({ + type: "error", + content: "Invalid workflow id", + }); + return; + } + + const body = { + workflow_id: workflowId, + }; + + if (isInitial) { + await handleInitialExecution(body, isStepExecution, executionAction); + } else { + setStepExecType(wfExecutionTypes[executionAction]); + body["execution_id"] = executionId; + body["execution_action"] = wfExecutionTypes[executionAction]; + + handleWfExecutionApi(body) + .then(() => {}) + .catch((err) => { + const errorDetail = + err?.response?.data?.errors?.length > 0 + ? err.response.data.errors[0].detail + : "Something went wrong"; + setAlertDetails({ + type: "error", + content: errorDetail, + }); + }); + } + }; + + const getRequestBody = (body) => { + const formData = new FormData(); + fileList.forEach((file) => { + formData.append("files", file); + }); + formData.append("workflow_id", body["workflow_id"]); + formData.append("execution_id", body["execution_id"]); + if (body["execution_action"]) { + formData.append("execution_action", body["execution_action"]); + } + return formData; + }; + + const shouldIncludeFile = (body) => { + return body["execution_id"] && body["execution_id"].length > 0; + }; + + const handleWfExecutionApi = async (body) => { + let header = { + "X-CSRFToken": sessionDetails?.csrfToken, + "Content-Type": "application/json", + }; + if (shouldIncludeFile(body) && apiOpsPresent && fileList.length > 0) { + body = getRequestBody(body); + header = { + "X-CSRFToken": sessionDetails?.csrfToken, + "Content-Type": "multipart/form-data", + }; + } + const requestOptions = { + method: "POST", + url: `/api/v1/unstract/${sessionDetails?.orgId}/workflow/execute/`, + headers: header, + data: body, + }; + + return axiosPrivate(requestOptions) + .then((res) => res) + .catch((err) => { + throw err; + }); + }; + + const handleDisable = (wfExecTypeIndex) => { + if (!isLoading) { + return ( + wfExecTypeIndex === 1 || wfExecTypeIndex === 2 || wfExecTypeIndex === 3 + ); + } + + if (loadingType === "GENERATE") { + return true; + } + + // We can assume that the "loadingType" value is always going to be "EXECUTE" from here onwards. + if (execType === "NORMAL") { + return true; + } + + // We can assume that the "execType" value is always going to be "STEP" from here onwards. + if (wfExecTypeIndex === 0 || wfExecTypeIndex === 4) { + return true; + } + + if ( + stepExecType === wfExecutionTypes[1] || + stepExecType === wfExecutionTypes[2] + ) { + return true; + } + + return stepExecType === wfExecutionTypes[wfExecTypeIndex]; + }; + + const handleClearStates = () => { + setExecType(""); + setStepExecType(""); + setExecutionId(""); + }; + + const createAPIDeployment = () => { + const workflowId = details?.id; + if (!workflowId) { + setAlertDetails({ + type: "error", + content: "Invalid workflow id", + }); + return; + } + setOpenAddApiModal(true); + }; + + const handleClearCache = () => { + const workflowId = details?.id; + + if (!workflowId) { + setAlertDetails({ + type: "error", + content: "Invalid workflow id", + }); + return; + } + + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/workflow/${workflowId}/clear-cache/`, + }; + + axiosPrivate(requestOptions) + .then((res) => { + const msg = res?.data; + setAlertDetails({ + type: "success", + content: msg, + }); + }) + .catch((err) => { + const msg = err?.response?.data || "Failed to clear cache."; + setAlertDetails({ + type: "error", + content: msg, + }); + }); + }; + + const handleClearFileMarker = () => { + const workflowId = details?.id; + + if (!workflowId) { + setAlertDetails({ + type: "error", + content: "Invalid workflow id", + }); + return; + } + + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/workflow/${workflowId}/clear-file-marker/`, + }; + + axiosPrivate(requestOptions) + .then((res) => { + const msg = res?.data; + setAlertDetails({ + type: "success", + content: msg, + }); + }) + .catch((err) => { + const msg = err?.response?.data || "Failed to clear file marker."; + setAlertDetails({ + type: "error", + content: msg, + }); + }); + }; + + return ( + <> +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {statusBarMsg} +
+
+ {openFileUploadModal && ( + + )} + {openAddApiModal && ( + + )} + + + ); +} + +Actions.propTypes = { + statusBarMsg: PropTypes.string, + initializeWfComp: PropTypes.func.isRequired, + stepLoader: PropTypes.bool.isRequired, +}; + +export { Actions }; diff --git a/frontend/src/components/agency/agency/Agency.css b/frontend/src/components/agency/agency/Agency.css new file mode 100644 index 000000000..3eb162ba6 --- /dev/null +++ b/frontend/src/components/agency/agency/Agency.css @@ -0,0 +1,59 @@ +/* Styles for Agency */ + +.agency-layout { + height: 100%; + display: flex; + flex-direction: column; +} + +.agency-sider-layout { + height: 100%; + background-color: transparent !important; +} + +.agency-layout2 { + flex: 1; + display: flex; + flex-direction: column; +} + +.agency-main { + flex: 1; +} + +.agency-sider-content { + height: 100%; + padding: 12px 12px 12px 0px; +} + +.agency-sider-content > div { + height: 100%; + background-color: var(--white); + /* background-color: #DAE3EC; */ +} + +.agency-actions { + padding: 0px 12px; +} + +.agency-footer { + padding: 12px; +} + +.agency-ide-logs { + height: 10vh; +} + +.agency-ide-collapse-panel { + background-color: var(--white); + border: none; + border-radius: 0px; +} + +.agency-ide-log-modal .ant-modal-content{ + height: 80vh; +} + +.agency-ide-log-modal .agency-ide-logs{ + height: 70vh !important; +} diff --git a/frontend/src/components/agency/agency/Agency.jsx b/frontend/src/components/agency/agency/Agency.jsx new file mode 100644 index 000000000..099a50bfe --- /dev/null +++ b/frontend/src/components/agency/agency/Agency.jsx @@ -0,0 +1,260 @@ +import { Button, Collapse, Layout, Modal } from "antd"; + +import { IslandLayout } from "../../../layouts/island-layout/IslandLayout"; +import { DisplayLogs } from "../../custom-tools/display-logs/DisplayLogs"; +import { Actions } from "../actions/Actions"; +import { WorkflowExecution } from "../workflow-execution/WorkflowExecution"; +import "./Agency.css"; + +import { + FullscreenExitOutlined, + FullscreenOutlined, + LeftOutlined, + RightOutlined, +} from "@ant-design/icons"; +import Sider from "antd/es/layout/Sider"; +import { useEffect, useState } from "react"; + +import { useSocketLogsStore } from "../../../store/socket-logs-store"; +import { useSocketMessagesStore } from "../../../store/socket-messages-store"; +import { useWorkflowStore } from "../../../store/workflow-store"; +import { LogsLabel } from "../logs-label/LogsLabel"; +import { SidePanel } from "../side-panel/SidePanel"; + +function Agency() { + const [isCollapsed, setIsCollapsed] = useState(false); + const [activeKey, setActiveKey] = useState([]); + const [steps, setSteps] = useState([]); + const [inputMd, setInputMd] = useState(""); + const [outputMd, setOutputMd] = useState(""); + const [statusBarMsg, setStatusBarMsg] = useState(""); + const [sourceMsg, setSourceMsg] = useState(""); + const [destinationMsg, setDestinationMsg] = useState(""); + const { message, setDefault } = useSocketMessagesStore(); + const { emptyLogs } = useSocketLogsStore(); + const workflowStore = useWorkflowStore(); + const { details, loadingType } = workflowStore; + const prompt = details?.prompt_text; + const [activeToolId, setActiveToolId] = useState(""); + const [prevLoadingType, setPrevLoadingType] = useState(""); + const [isUpdateSteps, setIsUpdateSteps] = useState(false); + const [stepLoader, setStepLoader] = useState(false); + const [showLogsModal, setShowLogsModal] = useState(false); + + const openLogsModal = () => { + setShowLogsModal(true); + }; + + const closeLogsModal = () => { + setShowLogsModal(false); + }; + + const genExtra = () => ( + { + // If you don't want click extra trigger collapse, you can prevent this: + openLogsModal(); + event.stopPropagation(); + }} + /> + ); + + const getItems = () => [ + { + key: "1", + label: activeKey?.length > 0 ? : "Logs", + children: ( +
+ +
+ ), + extra: genExtra(), + }, + ]; + + const handleCollapse = (keys) => { + setActiveKey(keys); + }; + + useEffect(() => { + if (prevLoadingType !== "EXECUTE") { + setIsUpdateSteps(true); + } + + setPrevLoadingType(loadingType); + }, [workflowStore]); + + useEffect(() => { + if (!isUpdateSteps) { + return; + } + setToolInstances(); + setIsUpdateSteps(false); + }, [isUpdateSteps, prompt]); + + const setToolInstances = () => { + const toolInstances = [...(details?.tool_instances || [])]; + setSteps(toolInstances); + }; + + const initializeWfComp = () => { + setToolInstances(); + setActiveToolId(""); + setInputMd(""); + setOutputMd(""); + setStatusBarMsg(""); + setDefault(); + emptyLogs(); + setSourceMsg(""); + setDestinationMsg(""); + }; + + useEffect(() => { + // Clean up function to clear all the socket messages + return () => { + setDefault(); + emptyLogs(); + }; + }, []); + + useEffect(() => { + if (Object.keys(message)?.length === 0) { + return; + } + + const state = message?.state; + const msgComp = message?.component; + if (state === "INPUT_UPDATE") { + setInputMd(message?.message); + return; + } + + if (state === "OUTPUT_UPDATE") { + setOutputMd(message?.message); + return; + } + + if (state === "MESSAGE") { + setStatusBarMsg(message?.message); + return; + } + + if (msgComp === "SOURCE" && state === "RUNNING") { + setActiveKey(""); + setSourceMsg(""); + setDestinationMsg(""); + const newSteps = [...steps].map((step) => { + step["progress"] = ""; + step["status"] = ""; + return step; + }); + setSteps(newSteps); + } + + if (msgComp === "SOURCE") { + const srcMsg = message?.state + ": " + message?.message; + setSourceMsg(srcMsg); + return; + } + + if (msgComp === "DESTINATION") { + const destMsg = message?.state + ": " + message?.message; + setDestinationMsg(destMsg); + setActiveToolId(""); + return; + } + + if (msgComp === "NEXT_STEP") { + setStepLoader((prev) => !prev); + return; + } + + const stepsCopy = [...(steps || [])]; + const newSteps = stepsCopy.map((step) => { + const stepObj = { ...step }; + if (stepObj?.id !== msgComp) { + return stepObj; + } + + setActiveToolId(msgComp); + stepObj["progress"] = message?.state; + stepObj["status"] = message?.message; + return stepObj; + }); + setSteps(newSteps); + }, [message]); + + return ( +
+ + + + + + +
+
+ +
+
+ {!isCollapsed && } +
+
+
+
+
+ +
+
+ + } + > + +
+ +
+
+
+
+ ); +} + +export { Agency }; diff --git a/frontend/src/components/agency/cards-list/CardList.css b/frontend/src/components/agency/cards-list/CardList.css new file mode 100644 index 000000000..5197ffcb5 --- /dev/null +++ b/frontend/src/components/agency/cards-list/CardList.css @@ -0,0 +1,30 @@ +.card-row { + height: 100%; +} +.card-col-div{ + width: 100%; +} +.card-typography{ + font-size: 12px; + font-weight: bold; +} +.card-col-details{ + padding: 10px 10px 0px; + border-radius: 0px 6px 6px 0px; +} +.wf-step-card-layout .active { + background-color: #DAE3EC; +} +.card-body > .ant-card-body{ + padding: 0; + cursor: pointer; +} +.step-name { + padding-left: 10px; +} +.tool-active { + border: 1px solid #3E7DC0; +} +.tool-dragging { + background-color: #DAE3EC; +} \ No newline at end of file diff --git a/frontend/src/components/agency/cards-list/CardsList.jsx b/frontend/src/components/agency/cards-list/CardsList.jsx new file mode 100644 index 000000000..939ec578c --- /dev/null +++ b/frontend/src/components/agency/cards-list/CardsList.jsx @@ -0,0 +1,195 @@ +import { CloseOutlined } from "@ant-design/icons"; +import { Card, Col, Image, Progress, Row, Typography } from "antd"; +import PropTypes from "prop-types"; +import { useRef } from "react"; +import { useDrag, useDrop } from "react-dnd"; + +import { handleException } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useSessionStore } from "../../../store/session-store"; +import { useToolSettingsStore } from "../../../store/tool-settings"; +import { useWorkflowStore } from "../../../store/workflow-store"; +import { ConfirmModal } from "../../widgets/confirm-modal/ConfirmModal"; +import "../step-card/StepCard.css"; +import "./CardList.css"; + +const CardsList = ({ step, index, activeTool, moveItem }) => { + const ref = useRef(null); + const { sessionDetails } = useSessionStore(); + const { toolSettings, setToolSettings, cleanUpToolSettings } = + useToolSettingsStore(); + const { deleteToolInstance } = useWorkflowStore(); + const { setAlertDetails } = useAlertStore(); + const axiosPrivate = useAxiosPrivate(); + const handleClick = (id, toolId, index) => { + const toolSettings = { id, tool_id: toolId }; + setToolSettings(toolSettings); + }; + const deleteStep = () => { + const requestOptions = { + method: "DELETE", + url: `/api/v1/unstract/${sessionDetails?.orgId}/tool_instance/${toolSettings?.id}/`, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + }, + }; + + axiosPrivate(requestOptions) + .then(() => { + deleteToolInstance(toolSettings?.id); + cleanUpToolSettings(); + setAlertDetails({ + type: "success", + content: "Successfully deleted the tool instance", + }); + }) + .catch((err) => { + setAlertDetails( + handleException(err, "Failed to delete the tool instance") + ); + }); + }; + const [, drop] = useDrop({ + accept: "STEP", + drop: (draggedItem) => { + if (!index && !draggedItem?.function_name) { + moveItem(draggedItem.index, index, draggedItem?.function_name); + } else if (draggedItem.index !== index && !draggedItem?.function_name) { + moveItem(draggedItem.index, index, draggedItem?.function_name); + } + }, + hover(item, monitor) { + if (!ref.current) { + return; + } + const dragIndex = item.index; + const hoverIndex = index; + // Don't replace items with themselves + if (dragIndex === hoverIndex) { + return; + } + // Determine rectangle on screen + const hoverBoundingRect = ref.current?.getBoundingClientRect(); + // Get vertical middle + const hoverMiddleY = + (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; + // Determine mouse position + const clientOffset = monitor.getClientOffset(); + // Get pixels to the top + const hoverClientY = clientOffset.y - hoverBoundingRect.top; + // Only perform the move when the mouse has crossed half of the items height + // When dragging downwards, only move when the cursor is below 50% + // When dragging upwards, only move when the cursor is above 50% + // Dragging downwards + if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { + return; + } + // Dragging upwards + if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { + return; + } + // Time to actually perform the action + moveItem(dragIndex, hoverIndex, item?.function_name, true); + // Note: we're mutating the monitor item here! + // Generally it's better to avoid mutations, + // but it's good here for the sake of performance + // to avoid expensive index searches. + item.index = hoverIndex; + }, + }); + const [{ isDragging }, drag] = useDrag({ + type: "STEP", + item: { index }, + collect: (monitor) => ({ + isDragging: monitor.isDragging(), + }), + }); + drag(drop(ref)); + return ( +
+ handleClick(step?.id, step?.tool_id, index)} + > + + +
+
+ + STEP + +
+
+ index + 1} + /> +
+
+ + +
+ + + + + +
+ + {step?.name} + +
+ + + {toolSettings?.id === step?.id && ( +
+ deleteStep()} + content="Want to delete this step" + > + + +
+ )} + +
+ + Status: {step?.status} + +
+ +
+
+
+ ); +}; + +CardsList.propTypes = { + step: PropTypes.object, + index: PropTypes.number.isRequired, + activeTool: PropTypes.string.isRequired, + moveItem: PropTypes.func.isRequired, +}; +export { CardsList }; diff --git a/frontend/src/components/agency/configuration-modal/ConfigurationModal.css b/frontend/src/components/agency/configuration-modal/ConfigurationModal.css new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/components/agency/configuration-modal/ConfigurationModal.jsx b/frontend/src/components/agency/configuration-modal/ConfigurationModal.jsx new file mode 100644 index 000000000..3e5597f76 --- /dev/null +++ b/frontend/src/components/agency/configuration-modal/ConfigurationModal.jsx @@ -0,0 +1,25 @@ +import { Modal } from "antd"; +import PropTypes from "prop-types"; + +import { Configuration } from "../configuration/Configuration"; + +function ConfigurationModal({ isOpen, setOpen }) { + return ( + setOpen(false)} + footer={false} + closable={true} + maskClosable={false} + > + + + ); +} + +ConfigurationModal.propTypes = { + isOpen: PropTypes.bool.isRequired, + setOpen: PropTypes.func.isRequired, +}; + +export { ConfigurationModal }; diff --git a/frontend/src/components/agency/configuration/Configuration.css b/frontend/src/components/agency/configuration/Configuration.css new file mode 100644 index 000000000..534b54fb2 --- /dev/null +++ b/frontend/src/components/agency/configuration/Configuration.css @@ -0,0 +1,10 @@ +/* Styles for Configuration */ + +.config-head { + padding-bottom: 10px; +} + +.config-head-typo { + font-size: 18px; + font-weight: 600; +} \ No newline at end of file diff --git a/frontend/src/components/agency/configuration/Configuration.jsx b/frontend/src/components/agency/configuration/Configuration.jsx new file mode 100644 index 000000000..e834e4625 --- /dev/null +++ b/frontend/src/components/agency/configuration/Configuration.jsx @@ -0,0 +1,135 @@ +import { Button, Space, Typography } from "antd"; +import PropTypes from "prop-types"; +import { createRef, useEffect, useState } from "react"; +import { useParams } from "react-router-dom"; + +import { handleException } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { RjsfFormLayout } from "../../../layouts/rjsf-form-layout/RjsfFormLayout"; +import { useAlertStore } from "../../../store/alert-store"; +import { useSessionStore } from "../../../store/session-store"; +import { useWorkflowStore } from "../../../store/workflow-store"; +import { CustomButton } from "../../widgets/custom-button/CustomButton"; +import "./Configuration.css"; + +function Configuration({ setOpen }) { + const formRef = createRef(null); + const [schema, setSchema] = useState({}); + const [formData, setFormData] = useState({}); + const [isSchemaLoading, setSchemaLoading] = useState(false); + const [isUpdateApiLoading, setUpdateApiLoading] = useState(false); + const { id } = useParams(); + const axiosPrivate = useAxiosPrivate(); + const { sessionDetails } = useSessionStore(); + const { projectName } = useWorkflowStore(); + const { setAlertDetails } = useAlertStore(); + + useEffect(() => { + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/workflow/${id}/settings/`, + }; + + setSchemaLoading(true); + axiosPrivate(requestOptions) + .then((res) => { + const data = res?.data; + setSchema(data?.schema || {}); + setFormData(data?.settings || {}); + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to load the form")); + }) + .finally(() => { + setSchemaLoading(false); + }); + }, []); + + const isFormValid = () => { + if (formRef) { + formRef?.current?.validateFields((errors, values) => { + if (errors) { + return false; + } + }); + } + return true; + }; + + const validateAndSubmit = (updatedFormData) => { + if (!isFormValid()) { + return; + } + handleSubmit(updatedFormData); + }; + + const handleSubmit = (updatedFormData) => { + setFormData(updatedFormData); + const body = { + workflow_name: projectName, + settings: updatedFormData, + }; + + const requestOptions = { + method: "PUT", + url: `/api/v1/unstract/${sessionDetails?.orgId}/workflow/${id}/`, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + "Content-Type": "application/json", + }, + data: body, + }; + + setUpdateApiLoading(true); + axiosPrivate(requestOptions) + .then(() => { + setAlertDetails({ + type: "success", + content: "Saved successfully", + }); + setOpen(false); + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to save")); + }) + .finally(() => { + setUpdateApiLoading(false); + }); + }; + + return ( +
+
+ + Configuration + +
+ +
+ + + + Save + + +
+
+
+ ); +} + +Configuration.propTypes = { + setOpen: PropTypes.func.isRequired, +}; + +export { Configuration }; diff --git a/frontend/src/components/agency/configure-connector-modal/ConfigureConnectorModal.css b/frontend/src/components/agency/configure-connector-modal/ConfigureConnectorModal.css new file mode 100644 index 000000000..0bc4478fa --- /dev/null +++ b/frontend/src/components/agency/configure-connector-modal/ConfigureConnectorModal.css @@ -0,0 +1,95 @@ +/* Styles for ConfigureConnectorModal */ + +.conn-modal-body { + height: 800px; + display: flex; + flex-direction: column; + overflow-y: hidden; +} + +.conn-modal-row { + flex: 1; + overflow-y: hidden; + border: 1px solid #D4D4D4; + border-radius: 8px; +} + +.conn-modal-col { + height: 100%; + display: flex; + flex-direction: column; +} + +.conn-modal-col-left { + background-color: var(--page-bg-3); +} + +.conn-modal-tab-body { + flex: 1; + overflow-y: hidden; +} + +.conn-modal-gap { + margin-bottom: 8px; +} + +.conn-modal-menu { + height: 100%; + overflow-y: auto; + background-color: transparent; +} + +.conn-modal-form-pad-right { + padding: 0px 8px 0px 8px; + border-right: 1px solid #D4D4D4; +} + +.conn-modal-form-pad-left { + padding: 4px 20px 0px 20px; +} + +.conn-modal-form-right { + padding: 12px 12px 0px 0px; + padding-right: 20px; + border-right: 1px solid #D4D4D4; + height: 100%; +} + +.conn-modal-form-left { + padding: 12px 0px 0px 12px; + padding-left: 20px; + height: 100%; +} + +.conn-modal-flex { + display: flex; + flex-direction: column; + height: 100%; + overflow-y: hidden; +} + +.conn-modal-flex-1 { + flex: 1; + overflow-y: auto; +} + +.form-right { + padding: 8px 8px 0px 0px; +} + +.sidebar-menu { + margin-top: 10px; + background-color: transparent; +} + +.sidebar-menu .ant-menu-item { + padding: 5px !important; +} + +.sidebar-menu .ant-menu-title-content { + margin-left: 5px; +} + +.conn-modal-col .ant-tabs-nav { + margin: 0px; +} \ No newline at end of file diff --git a/frontend/src/components/agency/configure-connector-modal/ConfigureConnectorModal.jsx b/frontend/src/components/agency/configure-connector-modal/ConfigureConnectorModal.jsx new file mode 100644 index 000000000..614956d83 --- /dev/null +++ b/frontend/src/components/agency/configure-connector-modal/ConfigureConnectorModal.jsx @@ -0,0 +1,117 @@ +import { Col, Modal, Row, Tabs, Typography } from "antd"; +import PropTypes from "prop-types"; +import { useState } from "react"; + +import { ListOfConnectors } from "../list-of-connectors/ListOfConnectors"; +import "./ConfigureConnectorModal.css"; +import { ConfigureFormsLayout } from "../configure-forms-layout/ConfigureFormsLayout"; +import { ManageFiles } from "../../input-output/manage-files/ManageFiles"; + +function ConfigureConnectorModal({ + open, + setOpen, + type, + selectedId, + setSelectedId, + handleUpdate, + filteredList, + connectorId, + connectorMetadata, + specConfig, + formDataConfig, + setFormDataConfig, + isSpecConfigLoading, +}) { + const [activeKey, setActiveKey] = useState("1"); + + const tabItems = [ + { + key: "1", + label: "Settings", + }, + { + key: "2", + label: "File System", + disabled: !connectorId, + }, + ]; + + const handleSelectItem = (e) => { + const id = e.key; + setSelectedId(id?.toString()); + }; + + const onTabChange = (key) => { + setActiveKey(key); + }; + + return ( + setOpen(false)} + centered + footer={null} + width={1200} + maskClosable={false} + > +
+ + Configure Connector + +
+ + + + + + + {activeKey === "1" && ( + + )} + {activeKey === "2" && } + + +
+ + ); +} + +ConfigureConnectorModal.propTypes = { + open: PropTypes.bool.isRequired, + setOpen: PropTypes.func.isRequired, + type: PropTypes.string.isRequired, + connectorId: PropTypes.string, + selectedId: PropTypes.string, + setSelectedId: PropTypes.func.isRequired, + handleUpdate: PropTypes.func.isRequired, + filteredList: PropTypes.array, + connectorMetadata: PropTypes.object.isRequired, + specConfig: PropTypes.object, + formDataConfig: PropTypes.object, + setFormDataConfig: PropTypes.func.isRequired, + isSpecConfigLoading: PropTypes.bool.isRequired, +}; + +export { ConfigureConnectorModal }; diff --git a/frontend/src/components/agency/configure-forms-layout/ConfigureFormsLayout.jsx b/frontend/src/components/agency/configure-forms-layout/ConfigureFormsLayout.jsx new file mode 100644 index 000000000..0544f8d3e --- /dev/null +++ b/frontend/src/components/agency/configure-forms-layout/ConfigureFormsLayout.jsx @@ -0,0 +1,83 @@ +import { Col, Row, Typography } from "antd"; +import PropTypes from "prop-types"; +import { SettingsForm } from "../settings-form/SettingsForm"; +import { AddSource } from "../../input-output/add-source/AddSource"; +import { EmptyState } from "../../widgets/empty-state/EmptyState"; + +function ConfigureFormsLayout({ + selectedId, + type, + handleUpdate, + editItemId, + connectorMetadata, + isConnAvailable, + specConfig, + formDataConfig, + setFormDataConfig, + isSpecConfigLoading, +}) { + return ( + + +
+ Connection Settings +
+
+ {!selectedId ? ( + + ) : ( + + )} +
+
+ + +
+ Configuration +
+
+ {!specConfig || Object.keys(specConfig)?.length === 0 ? ( + + ) : ( + + )} +
+
+ + + ); +} + +ConfigureFormsLayout.propTypes = { + selectedId: PropTypes.string.isRequired, + type: PropTypes.string.isRequired, + handleUpdate: PropTypes.func.isRequired, + editItemId: PropTypes.string, + connectorMetadata: PropTypes.object.isRequired, + isConnAvailable: PropTypes.bool.isRequired, + specConfig: PropTypes.object, + formDataConfig: PropTypes.object, + setFormDataConfig: PropTypes.func.isRequired, + isSpecConfigLoading: PropTypes.bool.isRequired, +}; + +export { ConfigureFormsLayout }; diff --git a/frontend/src/components/agency/ds-settings-card/DsSettingsCard.jsx b/frontend/src/components/agency/ds-settings-card/DsSettingsCard.jsx new file mode 100644 index 000000000..1af2e6815 --- /dev/null +++ b/frontend/src/components/agency/ds-settings-card/DsSettingsCard.jsx @@ -0,0 +1,336 @@ +import { + ExclamationCircleOutlined, + ExportOutlined, + ImportOutlined, + SettingOutlined, +} from "@ant-design/icons"; +import { + Button, + Col, + Image, + Row, + Select, + Space, + Tooltip, + Typography, +} from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import { handleException } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useSessionStore } from "../../../store/session-store"; +import { useWorkflowStore } from "../../../store/workflow-store"; +import SpaceWrapper from "../../widgets/space-wrapper/SpaceWrapper"; +import { ConfigureConnectorModal } from "../configure-connector-modal/ConfigureConnectorModal"; + +const tooltip = { + input: "Data Source Settings", + output: "Data Destination Settings", +}; + +const inputOptions = [ + { + value: "API", + label: "API", + }, + { + value: "FILESYSTEM", + label: "File System", + }, +]; + +function DsSettingsCard({ type, endpointDetails, message }) { + const [options, setOptions] = useState([...inputOptions]); + const [openModal, setOpenModal] = useState(false); + + const [listOfConnectors, setListOfConnectors] = useState([]); + const [filteredList, setFilteredList] = useState([]); + + const [connType, setConnType] = useState(null); + + const [connDetails, setConnDetails] = useState({}); + const [specConfig, setSpecConfig] = useState({}); + const [isSpecConfigLoading, setIsSpecConfigLoading] = useState(false); + const [formDataConfig, setFormDataConfig] = useState({}); + const [selectedId, setSelectedId] = useState(""); + const { sessionDetails } = useSessionStore(); + const { updateWorkflow } = useWorkflowStore(); + const { setAlertDetails } = useAlertStore(); + const axiosPrivate = useAxiosPrivate(); + + const icons = { + input: , + output: , + }; + + useEffect(() => { + if (endpointDetails?.connection_type !== connType) { + setConnType(endpointDetails?.connection_type); + } + + if (!endpointDetails?.connector_instance?.length) { + setConnDetails({}); + return; + } + + if (connDetails?.id === endpointDetails?.connector_instance) { + return; + } + + getSourceDetails(); + }, [endpointDetails]); + + useEffect(() => { + if (type === "output") { + setOptions(() => { + const newOptions = [...inputOptions]; + newOptions.push({ + value: "DATABASE", + label: "Database", + }); + return newOptions; + }); + return; + } + setOptions([...inputOptions]); + }, [type]); + + useEffect(() => { + const menuItems = []; + [...listOfConnectors].forEach((item) => { + if ( + endpointDetails?.connection_type && + item?.connector_mode.split("_").join("") !== + endpointDetails?.connection_type + ) { + return; + } + menuItems.push(getItem(item?.name, item?.id, sourceIcon(item?.icon))); + }); + setSelectedId(""); + setFilteredList(menuItems); + + if (!endpointDetails?.id) { + return; + } + + setFormDataConfig(endpointDetails.configuration || {}); + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/workflow/endpoint/${endpointDetails?.id}/settings/`, + }; + + setIsSpecConfigLoading(true); + axiosPrivate(requestOptions) + .then((res) => { + const data = res?.data; + setSpecConfig(data?.schema || {}); + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to load the spec")); + }) + .finally(() => { + setIsSpecConfigLoading(false); + }); + }, [connType, listOfConnectors]); + + useEffect(() => { + if (!type) { + return; + } + + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${ + sessionDetails?.orgId + }/supported_connectors/?type=${type.toUpperCase()}`, + }; + + axiosPrivate(requestOptions) + .then((res) => { + const data = res?.data; + setListOfConnectors(data || []); + }) + .catch((err) => { + setAlertDetails(handleException(err)); + }) + .finally(() => {}); + }, [type]); + + const sourceIcon = (src) => { + return ; + }; + + const getItem = (label, key, icon, children, type) => { + return { + key, + icon, + children, + label, + type, + }; + }; + + const handleUpdate = (updatedData, showSuccess) => { + const body = { ...endpointDetails, ...updatedData }; + + const requestOptions = { + method: "PUT", + url: `/api/v1/unstract/${sessionDetails?.orgId}/workflow/endpoint/${endpointDetails?.id}/`, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + "Content-Type": "application/json", + }, + data: body, + }; + + axiosPrivate(requestOptions) + .then((res) => { + const data = res?.data || {}; + const updatedData = {}; + if (type === "input") { + updatedData["source"] = data; + } else { + updatedData["destination"] = data; + } + updateWorkflow(updatedData); + if (showSuccess) { + setAlertDetails({ + type: "success", + content: "Successfully updated", + }); + } + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to update")); + }); + }; + + const getSourceDetails = () => { + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/connector/${endpointDetails?.connector_instance}/`, + }; + + axiosPrivate(requestOptions) + .then((res) => { + const data = res?.data; + data["connector_metadata"]["connectorName"] = + data?.connector_name || ""; + setConnDetails(data); + setSelectedId(data?.connector_id); + }) + .catch((err) => { + setAlertDetails(handleException(err)); + }); + }; + + return ( + <> + + + {icons[type]} + + + + + } + /> +
+
+ +
+
+ ); +} + +export { Tools }; diff --git a/frontend/src/components/agency/workflow-execution-layout/WorkflowExecutionMain.css b/frontend/src/components/agency/workflow-execution-layout/WorkflowExecutionMain.css new file mode 100644 index 000000000..568e55fb1 --- /dev/null +++ b/frontend/src/components/agency/workflow-execution-layout/WorkflowExecutionMain.css @@ -0,0 +1,28 @@ +/* Styles for WorkflowExecutionLayout */ + +.wf-exec-main-layout { + height: 100%; + overflow-y: hidden; +} + +.wf-exec-main-col-1 { + height: 100%; + display: flex; + flex-direction: column; + padding-right: 6px; + overflow-y: hidden; +} + +.wf-exec-main-col-2 { + height: 100%; + padding-left: 6px; +} + +.wf-exec-main-prompt { + padding-bottom: 6px; +} + +.wf-exec-main-steps { + flex: 1; + overflow: hidden; +} diff --git a/frontend/src/components/agency/workflow-execution-layout/WorkflowExecutionMain.jsx b/frontend/src/components/agency/workflow-execution-layout/WorkflowExecutionMain.jsx new file mode 100644 index 000000000..7748ebbbb --- /dev/null +++ b/frontend/src/components/agency/workflow-execution-layout/WorkflowExecutionMain.jsx @@ -0,0 +1,57 @@ +import { Col, Row } from "antd"; +import PropTypes from "prop-types"; + +import { Prompt } from "../prompt/Prompt"; +import { Steps } from "../steps/Steps"; +import "./WorkflowExecutionMain.css"; +import { InputOutput } from "../input-output/InputOutput"; + +function WorkflowExecutionMain({ + steps, + setSteps, + activeToolId, + inputMd, + outputMd, + sourceMsg, + destinationMsg, +}) { + return ( +
+ + +
+
+ +
+
+ +
+
+ + +
+ +
+ +
+
+ ); +} + +WorkflowExecutionMain.propTypes = { + steps: PropTypes.array, + setSteps: PropTypes.func, + activeToolId: PropTypes.string, + inputMd: PropTypes.string, + outputMd: PropTypes.string, + sourceMsg: PropTypes.string, + destinationMsg: PropTypes.string, +}; + +export { WorkflowExecutionMain }; diff --git a/frontend/src/components/agency/workflow-execution/WorkflowExecution.css b/frontend/src/components/agency/workflow-execution/WorkflowExecution.css new file mode 100644 index 000000000..adaa01cee --- /dev/null +++ b/frontend/src/components/agency/workflow-execution/WorkflowExecution.css @@ -0,0 +1,21 @@ +/* Styles for WorkflowExecution */ + +.wf-exec-layout { + height: 100%; + display: flex; + flex-direction: column; + padding: 12px; +} + +.wf-exec-heading { + margin-bottom: 6px; +} + +.wf-exec-heading-typo { + font-size: 18px; +} + +.wf-exec-main { + flex: 1; + overflow-y: hidden; +} diff --git a/frontend/src/components/agency/workflow-execution/WorkflowExecution.jsx b/frontend/src/components/agency/workflow-execution/WorkflowExecution.jsx new file mode 100644 index 000000000..7e2edf26a --- /dev/null +++ b/frontend/src/components/agency/workflow-execution/WorkflowExecution.jsx @@ -0,0 +1,48 @@ +import { Typography } from "antd"; +import PropTypes from "prop-types"; + +import "./WorkflowExecution.css"; +import { WorkflowExecutionMain } from "../workflow-execution-layout/WorkflowExecutionMain"; + +function WorkflowExecution({ + steps, + setSteps, + activeToolId, + inputMd, + outputMd, + sourceMsg, + destinationMsg, +}) { + return ( +
+
+ + Workflow + +
+
+ +
+
+ ); +} + +WorkflowExecution.propTypes = { + steps: PropTypes.array, + setSteps: PropTypes.func, + activeToolId: PropTypes.string, + inputMd: PropTypes.string, + outputMd: PropTypes.string, + sourceMsg: PropTypes.string, + destinationMsg: PropTypes.string, +}; + +export { WorkflowExecution }; diff --git a/frontend/src/components/agency/workflow-execution/workflow_actions.js b/frontend/src/components/agency/workflow-execution/workflow_actions.js new file mode 100644 index 000000000..787a24795 --- /dev/null +++ b/frontend/src/components/agency/workflow-execution/workflow_actions.js @@ -0,0 +1,8 @@ +const Actions = { + START: "START", + NEXT: "NEXT", + STOP: "STOP", + CONTINUE: "CONTINUE", +}; + +export default Actions; diff --git a/frontend/src/components/custom-tools/add-custom-tool-form-modal/AddCustomToolFormModal.css b/frontend/src/components/custom-tools/add-custom-tool-form-modal/AddCustomToolFormModal.css new file mode 100644 index 000000000..12f940646 --- /dev/null +++ b/frontend/src/components/custom-tools/add-custom-tool-form-modal/AddCustomToolFormModal.css @@ -0,0 +1,10 @@ +/* Styles for AddCustomToolForm */ + +.add-cus-tool-header { + font-size: 16px; + font-weight: bold; +} + +.add-cus-tool-gap { + margin-bottom: 16px; +} \ No newline at end of file diff --git a/frontend/src/components/custom-tools/add-custom-tool-form-modal/AddCustomToolFormModal.jsx b/frontend/src/components/custom-tools/add-custom-tool-form-modal/AddCustomToolFormModal.jsx new file mode 100644 index 000000000..01b8c462d --- /dev/null +++ b/frontend/src/components/custom-tools/add-custom-tool-form-modal/AddCustomToolFormModal.jsx @@ -0,0 +1,171 @@ +import { Input, Modal, Space, Typography } from "antd"; +import PropTypes from "prop-types"; + +import { CustomButton } from "../../widgets/custom-button/CustomButton"; +import SpaceWrapper from "../../widgets/space-wrapper/SpaceWrapper"; +import "./AddCustomToolFormModal.css"; + +import { useEffect, useState } from "react"; + +import { handleException } from "../../../helpers/GetStaticData"; +import { useAlertStore } from "../../../store/alert-store"; + +function AddCustomToolFormModal({ + open, + setOpen, + editItem, + setEditItem, + handleAddNewTool, +}) { + const [title, setTitle] = useState(""); + const [toolName, setToolName] = useState(""); + const [author, setAuthor] = useState(""); + const [description, setDescription] = useState(""); + const [icon, setIcon] = useState(""); + const [isEdit, setIsEdit] = useState(false); + const { setAlertDetails } = useAlertStore(); + + useEffect(() => { + setIsEdit(editItem && Object.keys(editItem)?.length > 0); + }, [editItem]); + + useEffect(() => { + if (!open) { + clearForm(); + } + }, [open]); + + useEffect(() => { + if (isEdit) { + setTitle("Edit Tool Information"); + setToolName(editItem?.tool_name || ""); + setAuthor(editItem?.author || ""); + setDescription(editItem?.description || ""); + setIcon(editItem?.icon || ""); + return; + } + setTitle("Add Tool Information"); + }, [isEdit]); + + const handleSubmit = (event) => { + event.preventDefault(); + if (!toolName.trim() || !author.trim() || !description.trim()) { + setAlertDetails({ + type: "error", + content: "Please add valid values in input fields", + }); + return; + } + + const body = { + tool_name: toolName, + author: author, + description: description, + icon: icon, + }; + handleAddNewTool(body) + .then((success) => { + setAlertDetails({ + type: "success", + content: `${isEdit ? "Updated" : "Added"} Successfully`, + }); + clearForm(); + }) + .catch((err) => { + const msg = `Failed to ${isEdit ? "update" : "add"}`; + setAlertDetails(handleException(err, msg)); + }); + }; + + const clearForm = () => { + setToolName(""); + setAuthor(""); + setDescription(""); + setIcon(""); + setEditItem({}); + setIsEdit(false); + }; + + return ( + setOpen(false)} + footer={null} + centered + maskClosable={false} + > +
+
+
+ + {title} + +
+
+ + Tool Name + setToolName(e.target.value)} + required + /> + +
+ + Author/Org Name + setAuthor(e.target.value)} + required + /> + +
+ + Description + setDescription(e.target.value)} + required + /> + +
+ + Icon + setIcon(e.target.value)} /> + + Enter the name of the icon from{" "} + + Google Fonts + + + +
+
+ + setOpen(false)}>Cancel + + Save + + +
+ + + ); +} + +AddCustomToolFormModal.propTypes = { + open: PropTypes.bool.isRequired, + setOpen: PropTypes.func.isRequired, + editItem: PropTypes.object.isRequired, + setEditItem: PropTypes.func.isRequired, + handleAddNewTool: PropTypes.func.isRequired, +}; + +export { AddCustomToolFormModal }; diff --git a/frontend/src/components/custom-tools/add-llm-profile-modal/AddLlmProfileModal.css b/frontend/src/components/custom-tools/add-llm-profile-modal/AddLlmProfileModal.css new file mode 100644 index 000000000..734fbdcb5 --- /dev/null +++ b/frontend/src/components/custom-tools/add-llm-profile-modal/AddLlmProfileModal.css @@ -0,0 +1,5 @@ +/* Styles for AddLlmProfile */ + +.add-llm-profile-row { + width: 100%; +} \ No newline at end of file diff --git a/frontend/src/components/custom-tools/add-llm-profile-modal/AddLlmProfileModal.jsx b/frontend/src/components/custom-tools/add-llm-profile-modal/AddLlmProfileModal.jsx new file mode 100644 index 000000000..4d742a70b --- /dev/null +++ b/frontend/src/components/custom-tools/add-llm-profile-modal/AddLlmProfileModal.jsx @@ -0,0 +1,416 @@ +import { CaretRightOutlined } from "@ant-design/icons"; +import { + Checkbox, + Col, + Collapse, + Form, + Input, + Modal, + Row, + Select, + Space, + Typography, + theme, +} from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import { handleException } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useCustomToolStore } from "../../../store/custom-tool-store"; +import { useSessionStore } from "../../../store/session-store"; +import { CustomButton } from "../../widgets/custom-button/CustomButton"; +import SpaceWrapper from "../../widgets/space-wrapper/SpaceWrapper"; +import "./AddLlmProfileModal.css"; + +function AddLlmProfileModal({ + open, + setOpen, + editLlmProfileId, + setEditLlmProfileId, +}) { + const [name, setName] = useState(""); + const [llm, setLlm] = useState(""); + const [chunkSize, setChunkSize] = useState(1024); + const [vectorDb, setVectorDb] = useState(""); + const [chunkOverlap, setChunkOverlap] = useState(128); + const [embeddingModel, setEmbeddingModel] = useState(""); + const [x2TextService, setX2TextService] = useState(""); + const [retrievalStrategy, setRetrievalStrategy] = useState(""); + const [similarityTopK, setSimilarityTopK] = useState(1); + const [section, setSection] = useState("Default"); + const [reIndex, setReIndex] = useState(false); + const [retrievalItems, setRetrievalItems] = useState([]); + const [llmItems, setLlmItems] = useState([]); + const [vectorDbItems, setVectorDbItems] = useState([]); + const [embeddingItems, setEmbeddingItems] = useState([]); + const [x2TextItems, setX2TextItems] = useState([]); + const [activeKey, setActiveKey] = useState(false); + const { sessionDetails } = useSessionStore(); + const { getDropdownItems, llmProfiles, updateCustomTool } = + useCustomToolStore(); + const { setAlertDetails } = useAlertStore(); + const axiosPrivate = useAxiosPrivate(); + const { token } = theme.useToken(); + const panelStyle = { + marginBottom: 16, + }; + + useEffect(() => { + setAdaptorProfilesDropdown(); + const data = getDropdownItems("retrieval_strategy"); + if (!data) { + return; + } + const items = Object.keys(data).map((name) => { + return { + value: data[name], + }; + }); + setRetrievalItems(items); + }, []); + + useEffect(() => { + if (open) { + return; + } + + setName(""); + setLlm(""); + setChunkSize(1024); + setVectorDb(""); + setChunkOverlap(128); + setEmbeddingModel(""); + setX2TextService(""); + setRetrievalStrategy(""); + setSimilarityTopK(1); + setSection("Default"); + setReIndex(false); + setEditLlmProfileId(null); + setActiveKey(false); + }, [open]); + + useEffect(() => { + if (!editLlmProfileId) { + return; + } + + const llmProfileDetails = [...llmProfiles].find( + (item) => item?.profile_id === editLlmProfileId + ); + + const llmItem = llmItems.find( + (item) => item?.label === llmProfileDetails?.llm + ); + + const vectorDbItem = vectorDbItems.find( + (item) => item?.label === llmProfileDetails?.vector_store + ); + + const embeddingItem = embeddingItems.find( + (item) => item?.label === llmProfileDetails?.embedding_model + ); + + const x2TextItem = x2TextItems.find( + (item) => item?.label === llmProfileDetails?.x2text + ); + + setName(llmProfileDetails?.profile_name); + setLlm(llmItem?.value || null); + setChunkSize(llmProfileDetails?.chunk_size); + setVectorDb(vectorDbItem?.value || null); + setChunkOverlap(llmProfileDetails?.chunk_overlap); + setEmbeddingModel(embeddingItem?.value || null); + setX2TextService(x2TextItem?.value || null); + setRetrievalStrategy(llmProfileDetails?.retrieval_strategy); + setSimilarityTopK(llmProfileDetails?.similarity_top_k); + setSection(llmProfileDetails?.section); + setReIndex(llmProfileDetails?.reindex); + setActiveKey(true); + }, [editLlmProfileId]); + + const setAdaptorProfilesDropdown = () => { + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/adapter`, + }; + + axiosPrivate(requestOptions) + .then((res) => { + const data = res?.data; + + data.forEach((item) => { + if (item?.adapter_type === "LLM") { + setLlmItems((prev) => { + const newItems = [...prev]; + newItems.push({ + value: item?.id, + label: item?.adapter_name, + }); + return newItems; + }); + } + if (item?.adapter_type === "VECTOR_DB") { + setVectorDbItems((prev) => { + const newItems = [...prev]; + newItems.push({ + value: item?.id, + label: item?.adapter_name, + }); + return newItems; + }); + } + if (item?.adapter_type === "EMBEDDING") { + setEmbeddingItems((prev) => { + const newItems = [...prev]; + newItems.push({ + value: item?.id, + label: item?.adapter_name, + }); + return newItems; + }); + } + if (item?.adapter_type === "X2TEXT") { + setX2TextItems((prev) => { + const newItems = [...prev]; + newItems.push({ + value: item?.id, + label: item?.adapter_name, + }); + return newItems; + }); + } + }); + }) + .catch((err) => { + setAlertDetails( + handleException( + err, + "Failed to get the dropdown list for LLM Adaptors" + ) + ); + }); + }; + + const getItems = (panelStyle) => [ + { + key: "1", + label: "Advanced Settings", + children: ( +
+ + setSimilarityTopK(e.target.value)} + /> + + + setName(e.target.value)} /> + + + + + setChunkSize(e.target.value)} + /> + + + + + + + setChunkOverlap(e.target.value)} + /> + + + + + setX2TextService(value)} + /> + + handleCaretIcon(isActive)} + size="small" + style={{ + background: token.colorBgContainer, + }} + items={getItems(panelStyle)} + activeKey={activeKey && "1"} + onChange={handleCollapse} + /> +
+ +
+ + + setOpen(false)}>Cancel + + {editLlmProfileId ? "Update" : "Add"} + + + + + + ); +} + +AddLlmProfileModal.propTypes = { + open: PropTypes.bool.isRequired, + setOpen: PropTypes.func.isRequired, + editLlmProfileId: PropTypes.string, + setEditLlmProfileId: PropTypes.func.isRequired, +}; + +export { AddLlmProfileModal }; diff --git a/frontend/src/components/custom-tools/combined-output/CombinedOutput.css b/frontend/src/components/custom-tools/combined-output/CombinedOutput.css new file mode 100644 index 000000000..13302b7e9 --- /dev/null +++ b/frontend/src/components/custom-tools/combined-output/CombinedOutput.css @@ -0,0 +1,39 @@ +/* Styles for CombinedOutput */ + +.combined-op-layout { + display: flex; + flex-direction: column; + height: 100%; + overflow-y: hidden; +} + +.combined-op-header { + display: flex; + margin-top: 7px; +} + +.combined-op-segment { + margin-left: auto; +} + +.combined-op-body { + flex: 1; + overflow-y: auto; +} + +.combined-op-divider { + margin-bottom: 10px; +} + +.code-snippet { + border: 1px solid #ECEFF3; +} + +.code-snippet > .language-javascript { + margin: 0px !important; + height: 100%; +} + +.combined-op-layout .gap { + margin-bottom: 12px; +} diff --git a/frontend/src/components/custom-tools/combined-output/CombinedOutput.jsx b/frontend/src/components/custom-tools/combined-output/CombinedOutput.jsx new file mode 100644 index 000000000..da3db4600 --- /dev/null +++ b/frontend/src/components/custom-tools/combined-output/CombinedOutput.jsx @@ -0,0 +1,141 @@ +import { Button, Segmented, Space } from "antd"; +import jsYaml from "js-yaml"; +import Prism from "prismjs"; +import "prismjs/components/prism-json"; +import "prismjs/plugins/line-numbers/prism-line-numbers.css"; +import "prismjs/plugins/line-numbers/prism-line-numbers.js"; +import "prismjs/themes/prism.css"; +import { useEffect, useState } from "react"; + +import { handleException, promptType } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useCustomToolStore } from "../../../store/custom-tool-store"; +import { useSessionStore } from "../../../store/session-store"; +import { SpinnerLoader } from "../../widgets/spinner-loader/SpinnerLoader"; +import "./CombinedOutput.css"; + +const outputTypes = { + json: "JSON", + yaml: "YAML", +}; + +function CombinedOutput() { + const [combinedOutput, setCombinedOutput] = useState({}); + const [yamlData, setYamlData] = useState(null); + const [selectedOutputType, setSelectedOutputType] = useState( + outputTypes.json + ); + const [isOutputLoading, setIsOutputLoading] = useState(false); + const { details, selectedDoc } = useCustomToolStore(); + const { sessionDetails } = useSessionStore(); + const { setAlertDetails } = useAlertStore(); + const axiosPrivate = useAxiosPrivate(); + + useEffect(() => { + if (!selectedDoc) { + return; + } + + setIsOutputLoading(true); + handleOutputApiRequest() + .then((res) => { + const data = res?.data || []; + const prompts = details?.prompts; + const output = {}; + prompts.forEach((item) => { + if (item?.prompt_type === promptType.notes) { + return; + } + output[item?.prompt_key] = ""; + + const outputDetails = data.find( + (outputValue) => + outputValue?.prompt_id === item?.prompt_id && + outputValue?.profile_manager === item?.profile_manager + ); + + if (!outputDetails) { + return; + } + + output[item?.prompt_key] = outputDetails?.output || ""; + }); + setCombinedOutput(output); + + const yamlDump = jsYaml.dump(output); + setYamlData(yamlDump); + }) + .catch((err) => { + setAlertDetails( + handleException(err, "Failed to generate combined output") + ); + }) + .finally(() => { + setIsOutputLoading(false); + }); + }, [selectedDoc]); + + useEffect(() => { + Prism.highlightAll(); + }, [combinedOutput, selectedOutputType]); + + const handleOutputTypeChange = (value) => { + setSelectedOutputType(value); + }; + + const handleOutputApiRequest = async () => { + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/prompt-output/?tool_id=${details?.tool_id}&doc_name=${selectedDoc}`, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + }, + }; + + return axiosPrivate(requestOptions) + .then((res) => res) + .catch((err) => { + throw err; + }); + }; + + if (isOutputLoading) { + return ; + } + + return ( +
+
+ +
+ +
+
+
+ +
+
+
+
+ {combinedOutput && ( +
+            
+              {selectedOutputType === outputTypes.json
+                ? JSON.stringify(combinedOutput, null, 2)
+                : yamlData}
+            
+          
+ )} +
+
+
+ ); +} + +export { CombinedOutput }; diff --git a/frontend/src/components/custom-tools/custom-synonyms-modal/CustomSynonymsModal.css b/frontend/src/components/custom-tools/custom-synonyms-modal/CustomSynonymsModal.css new file mode 100644 index 000000000..f67c52af6 --- /dev/null +++ b/frontend/src/components/custom-tools/custom-synonyms-modal/CustomSynonymsModal.css @@ -0,0 +1 @@ +/* Styles for CustomSynonymsModal */ \ No newline at end of file diff --git a/frontend/src/components/custom-tools/custom-synonyms-modal/CustomSynonymsModal.jsx b/frontend/src/components/custom-tools/custom-synonyms-modal/CustomSynonymsModal.jsx new file mode 100644 index 000000000..798d4cf7d --- /dev/null +++ b/frontend/src/components/custom-tools/custom-synonyms-modal/CustomSynonymsModal.jsx @@ -0,0 +1,26 @@ +import { Modal } from "antd"; +import PropTypes from "prop-types"; +import { CustomSynonyms } from "../custom-synonyms/CustomSynonyms"; + +function CustomSynonymsModal({ open, setOpen }) { + return ( + setOpen(false)} + centered + footer={null} + width={800} + maskClosable={false} + > + + + ); +} + +CustomSynonymsModal.propTypes = { + open: PropTypes.bool.isRequired, + setOpen: PropTypes.func.isRequired, +}; + +export { CustomSynonymsModal }; diff --git a/frontend/src/components/custom-tools/custom-synonyms/CustomSynonyms.css b/frontend/src/components/custom-tools/custom-synonyms/CustomSynonyms.css new file mode 100644 index 000000000..d8c4727ab --- /dev/null +++ b/frontend/src/components/custom-tools/custom-synonyms/CustomSynonyms.css @@ -0,0 +1,10 @@ +/* Styles for CustomSynonyms */ + +.cus-syn-select { + width: 100%; + border: none; +} + +.cus-syn-del { + font-size: 10px; +} \ No newline at end of file diff --git a/frontend/src/components/custom-tools/custom-synonyms/CustomSynonyms.jsx b/frontend/src/components/custom-tools/custom-synonyms/CustomSynonyms.jsx new file mode 100644 index 000000000..f964fdd52 --- /dev/null +++ b/frontend/src/components/custom-tools/custom-synonyms/CustomSynonyms.jsx @@ -0,0 +1,218 @@ +import { DeleteOutlined, PlusOutlined } from "@ant-design/icons"; +import { Button, Input, Select, Space, Table, Typography } from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import { handleException } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useCustomToolStore } from "../../../store/custom-tool-store"; +import { useSessionStore } from "../../../store/session-store"; +import { ConfirmModal } from "../../widgets/confirm-modal/ConfirmModal"; +import { CustomButton } from "../../widgets/custom-button/CustomButton"; +import SpaceWrapper from "../../widgets/space-wrapper/SpaceWrapper"; +import "./CustomSynonyms.css"; + +const columns = [ + { + title: "Word", + dataIndex: "word", + key: "word", + width: 200, + }, + { + title: "Synonyms", + dataIndex: "synonyms", + key: "synonyms", + }, + { + title: "", + dataIndex: "delete", + key: "delete", + width: 30, + }, +]; + +function CustomSynonyms({ setOpen }) { + const [synonyms, setSynonyms] = useState([]); + const [rows, setRows] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const { sessionDetails } = useSessionStore(); + const { details, updateCustomTool } = useCustomToolStore(); + const { setAlertDetails } = useAlertStore(); + const axiosPrivate = useAxiosPrivate(); + + useEffect(() => { + const promptGrammar = details?.prompt_grammer; + if (!promptGrammar || Object.keys(promptGrammar).length === 0) { + setSynonyms([]); + return; + } + + const updatedSynonyms = Object.keys(promptGrammar).map((word, index) => { + const value = promptGrammar[word]; + return { + key: index, + word, + synonyms: value, + }; + }); + + setSynonyms(updatedSynonyms); + }, [details]); + + useEffect(() => { + if (!synonyms || synonyms.length === 0) { + setRows([]); + return; + } + + const data = [...synonyms].map((item, index) => { + const word = item?.word; + const listOfSynonyms = item?.synonyms || []; + return { + key: index, + word: ( + + handleChange(index, "word", event.target.value) + } + /> + ), + synonyms: ( + + +
+
+
+ + Author/Org Name + + +
+
+
+ + Description + + +
+
+
+ + Search Icons +
+ + + Choose icons from here -{" "} + + fonts.google.com/icons + + +
+
+
+
+
+ ); +} + +export { EditToolInfo }; diff --git a/frontend/src/components/custom-tools/editable-text/EditableText.css b/frontend/src/components/custom-tools/editable-text/EditableText.css new file mode 100644 index 000000000..8cf908e74 --- /dev/null +++ b/frontend/src/components/custom-tools/editable-text/EditableText.css @@ -0,0 +1,17 @@ +/* Styles for EditableText */ + +.editable-text { + width: 100%; +} + +.edit-text-display { + width: 100%; + padding: 0px 6px; + border: 1px solid transparent; + border-radius: 4px; +} + +.edit-text-display-hover:hover { + border: 1px solid #bdbdbd; + border-radius: 4px; +} \ No newline at end of file diff --git a/frontend/src/components/custom-tools/editable-text/EditableText.jsx b/frontend/src/components/custom-tools/editable-text/EditableText.jsx new file mode 100644 index 000000000..ac5b14b00 --- /dev/null +++ b/frontend/src/components/custom-tools/editable-text/EditableText.jsx @@ -0,0 +1,110 @@ +import { Input } from "antd"; +import { useCallback, useEffect, useRef, useState } from "react"; +import PropTypes from "prop-types"; +import debounce from "lodash/debounce"; + +import "./EditableText.css"; +import { useCustomToolStore } from "../../../store/custom-tool-store"; + +function EditableText({ + isEditing, + setIsEditing, + promptId, + defaultText, + handleChange, + isTextarea, +}) { + const [text, setText] = useState(""); + const [isHovered, setIsHovered] = useState(false); + const divRef = useRef(null); + const { disableLlmOrDocChange } = useCustomToolStore(); + + useEffect(() => { + setText(defaultText); + }, [defaultText]); + + useEffect(() => { + // Attach the event listener when the component mounts + document.addEventListener("click", handleClickOutside); + + // Clean up the event listener when the component unmounts + return () => { + document.removeEventListener("click", handleClickOutside); + }; + }, []); + + const handleBlur = () => { + setIsEditing(false); + }; + + const handleTextChange = (event) => { + const value = event.target.value; + setText(value); + onSearchDebounce(event); + }; + + const onSearchDebounce = useCallback( + debounce((event) => { + handleChange(event, promptId, false, true); + }, 1000), + [] + ); + + const handleClickOutside = (event) => { + if (divRef.current && !divRef.current.contains(event.target)) { + // Clicked outside the div + setIsEditing(false); + } + }; + + if (isTextarea) { + return ( + setIsHovered(true)} + onMouseOut={() => setIsHovered(false)} + onBlur={handleBlur} + onClick={() => setIsEditing(true)} + disabled={disableLlmOrDocChange.includes(promptId)} + /> + ); + } + + return ( + setIsHovered(true)} + onMouseOut={() => setIsHovered(false)} + onBlur={handleBlur} + onClick={() => setIsEditing(true)} + disabled={disableLlmOrDocChange.includes(promptId)} + /> + ); +} + +EditableText.propTypes = { + isEditing: PropTypes.bool.isRequired, + setIsEditing: PropTypes.func.isRequired, + promptId: PropTypes.string.isRequired, + defaultText: PropTypes.string.isRequired, + handleChange: PropTypes.func.isRequired, + isTextarea: PropTypes.bool, +}; + +export { EditableText }; diff --git a/frontend/src/components/custom-tools/eval-metric-tag/EvalMetricTag.css b/frontend/src/components/custom-tools/eval-metric-tag/EvalMetricTag.css new file mode 100644 index 000000000..1f3328f50 --- /dev/null +++ b/frontend/src/components/custom-tools/eval-metric-tag/EvalMetricTag.css @@ -0,0 +1,68 @@ +/* Styles for EvalMetricTag */ + +.eval-metric-tag { + border: none; + margin-top: 1px; + margin-bottom: 2px; + margin-right: 5px; + padding-inline: 0px; +} + +.eval-metric-tag .eval-metric-tag-part { + margin: 0px; + border-top: 2px solid; + border-bottom: 2px solid; + border-radius: 0px; + background-color: white; +} + +.eval-metric-tag .eval-metric-tag-begin { + border-left: 2px solid; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} + +.eval-metric-tag .eval-metric-tag-end { + border-right: 2px solid; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +.eval-metric-tag .eval-metric-tag-name { + border-left: 2px solid; + border-right: 2px solid; + cursor: default; +} + +.eval-metric-tag .eval-metric-tag-type-quality { + border-color: #B471DE; +} + +.eval-metric-tag .eval-metric-tag-type-security { + border-color: #E8A400; +} + +.eval-metric-tag .eval-metric-tag-type-guidance { + border-color: #0097D8; +} + +.eval-metric-tag .eval-metric-tag-value { + color: white; + font-weight: 600; + cursor: default; +} + +.eval-metric-tag .eval-metric-tag-value-pass { + background-color: #99C633; + border-color: #99C633; +} + +.eval-metric-tag .eval-metric-tag-value-fail { + background-color: #FF718A; + border-color: #FF718A; +} + +.eval-metric-tag .eval-metric-tag-value-disabled { + background-color: #B4C2CF; + border-color: #B4C2CF; +} \ No newline at end of file diff --git a/frontend/src/components/custom-tools/eval-metric-tag/EvalMetricTag.jsx b/frontend/src/components/custom-tools/eval-metric-tag/EvalMetricTag.jsx new file mode 100644 index 000000000..9d34f9142 --- /dev/null +++ b/frontend/src/components/custom-tools/eval-metric-tag/EvalMetricTag.jsx @@ -0,0 +1,68 @@ +import { ExperimentOutlined } from "@ant-design/icons"; +import { Tag, Tooltip } from "antd"; +import PropTypes from "prop-types"; + +import "./EvalMetricTag.css"; + +/* + e.g. + { + "release": "stable", + "id": "correctness", + "type": "quality", + "name": "Correctness", + "value": "4.72 / 5", + "status": "pass|failed|disabled" + } + */ +function EvalMetricTag({ metric }) { + if (!metric?.name) { + return <>; + } + + return ( + // overlayStyle is required for adding line breaks in tooltip text + + + + {metric?.release === "stable" ? ( + "" + ) : ( + <> + + + +   + + )} + {metric?.name} + + + {metric?.status !== "disabled" ? metric?.value : "--"} + + + + ); +} + +EvalMetricTag.propTypes = { + metric: PropTypes.object.isRequired, +}; + +export { EvalMetricTag }; diff --git a/frontend/src/components/custom-tools/eval-modal/EvalModal.jsx b/frontend/src/components/custom-tools/eval-modal/EvalModal.jsx new file mode 100644 index 000000000..662a4ac04 --- /dev/null +++ b/frontend/src/components/custom-tools/eval-modal/EvalModal.jsx @@ -0,0 +1,155 @@ +import { InfoCircleOutlined } from "@ant-design/icons"; +import { + Checkbox, + Form, + Modal, + Space, + Switch, + Tooltip, + Typography, +} from "antd"; +import PropTypes from "prop-types"; +import SpaceWrapper from "../../widgets/space-wrapper/SpaceWrapper"; + +function EvalModal({ open, setOpen, promptDetails, handleChange }) { + return ( + setOpen(false)} + maskClosable={false} + footer={null} + centered + > + + + Evaluation Settings + +
+ + + { + handleChange(value, promptDetails?.prompt_id, "evaluate"); + }} + /> + Enable evaluation + + + + +
+ + Quality Metrics + + + { + handleChange( + e.target.checked, + promptDetails?.prompt_id, + "eval_quality_faithfulness" + ); + }} + /> + Faithfulness + + + + + + { + handleChange( + e.target.checked, + promptDetails?.prompt_id, + "eval_quality_relevance" + ); + }} + /> + Relevance + + + + + + +
+ + Security Metrics + + { + handleChange( + e.target.checked, + promptDetails?.prompt_id, + "eval_security_pii" + ); + }} + /> + PII + + + + + +
+ + Guidance Metrics + + { + handleChange( + e.target.checked, + promptDetails?.prompt_id, + "eval_guidance_toxicity" + ); + }} + /> + Toxicity + + + + + + { + handleChange( + e.target.checked, + promptDetails?.prompt_id, + "eval_guidance_completeness" + ); + }} + /> + Completeness + + + + + + + + + + ); +} + +EvalModal.propTypes = { + open: PropTypes.bool.isRequired, + setOpen: PropTypes.func.isRequired, + promptDetails: PropTypes.object.isRequired, + handleChange: PropTypes.func.isRequired, +}; + +export { EvalModal }; diff --git a/frontend/src/components/custom-tools/footer-layout/FooterLayout.css b/frontend/src/components/custom-tools/footer-layout/FooterLayout.css new file mode 100644 index 000000000..8266e99b9 --- /dev/null +++ b/frontend/src/components/custom-tools/footer-layout/FooterLayout.css @@ -0,0 +1,5 @@ +/* Styles for FooterLayout */ + +.tool-ide-main-footer-layout { + padding: 8px 14px; +} \ No newline at end of file diff --git a/frontend/src/components/custom-tools/footer-layout/FooterLayout.jsx b/frontend/src/components/custom-tools/footer-layout/FooterLayout.jsx new file mode 100644 index 000000000..211a88023 --- /dev/null +++ b/frontend/src/components/custom-tools/footer-layout/FooterLayout.jsx @@ -0,0 +1,17 @@ +import PropTypes from "prop-types"; + +import "./FooterLayout.css"; + +function FooterLayout({ children }) { + return ( +
+ {children} +
+ ); +} + +FooterLayout.propTypes = { + children: PropTypes.any.isRequired, +}; + +export { FooterLayout }; diff --git a/frontend/src/components/custom-tools/footer/Footer.css b/frontend/src/components/custom-tools/footer/Footer.css new file mode 100644 index 000000000..2a8b58d6d --- /dev/null +++ b/frontend/src/components/custom-tools/footer/Footer.css @@ -0,0 +1,7 @@ +/* Styles for ToolsMainFooter */ + +.tool-ide-main-footer { + display: flex; + justify-content: space-between; + margin-left: auto; +} \ No newline at end of file diff --git a/frontend/src/components/custom-tools/footer/Footer.jsx b/frontend/src/components/custom-tools/footer/Footer.jsx new file mode 100644 index 000000000..039b0ec08 --- /dev/null +++ b/frontend/src/components/custom-tools/footer/Footer.jsx @@ -0,0 +1,45 @@ +import PropTypes from "prop-types"; +import { Button } from "antd"; +import { PlusOutlined } from "@ant-design/icons"; + +import "./Footer.css"; +import { FooterLayout } from "../footer-layout/FooterLayout"; +import { promptType } from "../../../helpers/GetStaticData"; + +function Footer({ activeKey, addPromptInstance }) { + if (activeKey === "1") { + return ( + +
+
+ +
+
+ +
+
+
+ ); + } + + return <>; +} + +Footer.propTypes = { + activeKey: PropTypes.string.isRequired, + addPromptInstance: PropTypes.func.isRequired, +}; + +export { Footer }; diff --git a/frontend/src/components/custom-tools/generate-index/GenerateIndex.css b/frontend/src/components/custom-tools/generate-index/GenerateIndex.css new file mode 100644 index 000000000..05d65dba5 --- /dev/null +++ b/frontend/src/components/custom-tools/generate-index/GenerateIndex.css @@ -0,0 +1,21 @@ +/* Styles for GenerateIndex */ + +.gen-index-text { + font-size: 16px; +} + +.gen-index-progress { + color: #FAAD14; +} + +.gen-index-success { + color: #52C41A; +} + +.gen-index-fail { + color: #ff4242; +} + +.gen-index-icon { + font-size: 24px; +} \ No newline at end of file diff --git a/frontend/src/components/custom-tools/generate-index/GenerateIndex.jsx b/frontend/src/components/custom-tools/generate-index/GenerateIndex.jsx new file mode 100644 index 000000000..d9dcb0e85 --- /dev/null +++ b/frontend/src/components/custom-tools/generate-index/GenerateIndex.jsx @@ -0,0 +1,80 @@ +import { + CheckCircleFilled, + CloseCircleFilled, + ExclamationCircleFilled, +} from "@ant-design/icons"; +import { Col, Row, Typography } from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import "./GenerateIndex.css"; + +function GenerateIndex({ isGeneratingIndex, result }) { + const [text, setText] = useState(""); + const [subText, setSubText] = useState(""); + + useEffect(() => { + if (isGeneratingIndex) { + setText("Generating Index"); + setSubText("The index will take some time to create."); + return; + } + + if (result === "SUCCESS") { + setText("Successful Index"); + setSubText("Index is ready for inspection."); + return; + } + + if (result === "FAILED") { + setText("Failed to Index"); + setSubText("Please try again"); + return; + } + + setText(""); + setSubText(""); + }, [isGeneratingIndex]); + + return ( +
+
+ + +
+ {isGeneratingIndex ? ( + + ) : ( + <> + {result === "SUCCESS" ? ( + + ) : ( + + )} + + )} +
+ + + {text} + +
+
+
+ + + + {subText} + + +
+
+ ); +} + +GenerateIndex.propTypes = { + isGeneratingIndex: PropTypes.bool.isRequired, + result: PropTypes.string, +}; + +export { GenerateIndex }; diff --git a/frontend/src/components/custom-tools/header/Header.css b/frontend/src/components/custom-tools/header/Header.css new file mode 100644 index 000000000..a451ce0d3 --- /dev/null +++ b/frontend/src/components/custom-tools/header/Header.css @@ -0,0 +1,31 @@ +/* Styles for Header */ + +.custom-tools-header-layout { + padding: 8px; + background-color: #F5F7F9; + display: flex; + align-items: center; +} + +.custom-tools-header-btns { + display: flex; + justify-content: space-between; + margin-left: auto; +} + +.custom-tools-header-btns > div { + padding: 0px 5px; +} + +.custom-tools-name { + padding: 0px 8px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.custom-tools-header-v-divider { + border-right: 1px #D9D9D9 solid; + padding: 0; + margin: 0px 5px; +} \ No newline at end of file diff --git a/frontend/src/components/custom-tools/header/Header.jsx b/frontend/src/components/custom-tools/header/Header.jsx new file mode 100644 index 000000000..498512cd8 --- /dev/null +++ b/frontend/src/components/custom-tools/header/Header.jsx @@ -0,0 +1,157 @@ +import { + ArrowLeftOutlined, + CodeOutlined, + DiffOutlined, + EditOutlined, + ExportOutlined, + FilePdfOutlined, + FileTextOutlined, + MessageOutlined, +} from "@ant-design/icons"; +import { Button, Tooltip, Typography } from "antd"; +import PropTypes from "prop-types"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import "./Header.css"; + +import { handleException } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useCustomToolStore } from "../../../store/custom-tool-store"; +import { useSessionStore } from "../../../store/session-store"; +import { CustomButton } from "../../widgets/custom-button/CustomButton"; +import { PreAndPostAmbleModal } from "../pre-and-post-amble-modal/PreAndPostAmbleModal"; + +function Header({ + setOpenCusSynonymsModal, + setOpenManageDocsModal, + setOpenManageLlmModal, + handleUpdateTool, +}) { + const [openPreOrPostAmbleModal, setOpenPreOrPostAmbleModal] = useState(false); + const [preOrPostAmble, setPreOrPostAmble] = useState(""); + const [isExportLoading, setIsExportLoading] = useState(false); + const { details } = useCustomToolStore(); + const { sessionDetails } = useSessionStore(); + const { setAlertDetails } = useAlertStore(); + const axiosPrivate = useAxiosPrivate(); + const navigate = useNavigate(); + + const handleOpenPreOrPostAmbleModal = (type) => { + setOpenPreOrPostAmbleModal(true); + setPreOrPostAmble(type); + }; + const handleClosePreOrPostAmbleModal = () => { + setOpenPreOrPostAmbleModal(false); + setPreOrPostAmble(""); + }; + + const handleExport = () => { + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/export/?prompt_registry_id=${details?.tool_id}`, + }; + + setIsExportLoading(true); + axiosPrivate(requestOptions) + .then(() => { + setAlertDetails({ + type: "success", + content: "Custom tool exported successfully", + }); + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to export")); + }) + .finally(() => { + setIsExportLoading(false); + }); + }; + + return ( +
+
+ +
+
+ {details?.tool_name} +
+
+ +
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+ + + +
+
+ + + +
+
+
+ + + + + +
+
+ +
+ ); +} + +Header.propTypes = { + setOpenCusSynonymsModal: PropTypes.func.isRequired, + setOpenManageDocsModal: PropTypes.func.isRequired, + setOpenManageLlmModal: PropTypes.func.isRequired, + handleUpdateTool: PropTypes.func.isRequired, +}; + +export { Header }; diff --git a/frontend/src/components/custom-tools/list-of-tools/ListOfTools.css b/frontend/src/components/custom-tools/list-of-tools/ListOfTools.css new file mode 100644 index 000000000..602171c75 --- /dev/null +++ b/frontend/src/components/custom-tools/list-of-tools/ListOfTools.css @@ -0,0 +1,45 @@ +/* Styles for ListOfTools */ + +.list-of-tools-layout { + height: 100%; + background-color: var(--page-bg-2); + padding: 12px; +} + +.list-of-tools-island { + background-color: var(--page-bg-1); + height: 100%; + padding: 20px; +} + +.list-of-tools-wrap { + height: 100%; + display: flex; + flex-direction: column; +} + +.list-of-tools-header { + display: grid; + grid-template-columns: auto 1fr; +} + +.list-of-tools-title { + font-size: 18px; + font-weight: 600; +} + +.list-of-tools-header2 { + display: grid; + grid-auto-flow: column; + column-gap: 10px; + justify-self: end; +} + +.list-of-tools-divider { + margin-top: 12px; +} + +.list-of-tools-body { + flex: 1; + overflow-y: auto; +} \ No newline at end of file diff --git a/frontend/src/components/custom-tools/list-of-tools/ListOfTools.jsx b/frontend/src/components/custom-tools/list-of-tools/ListOfTools.jsx new file mode 100644 index 000000000..9a5ec279b --- /dev/null +++ b/frontend/src/components/custom-tools/list-of-tools/ListOfTools.jsx @@ -0,0 +1,233 @@ +import { + AppstoreOutlined, + BarsOutlined, + PlusOutlined, +} from "@ant-design/icons"; +import { Input, Segmented, Typography } from "antd"; +import debounce from "lodash/debounce"; +import isEmpty from "lodash/isEmpty"; +import { useCallback, useEffect, useState } from "react"; + +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useSessionStore } from "../../../store/session-store"; +import { CustomButton } from "../../widgets/custom-button/CustomButton"; +import { AddCustomToolFormModal } from "../add-custom-tool-form-modal/AddCustomToolFormModal"; +import { ViewTools } from "../view-tools/ViewTools"; + +import { handleException } from "../../../helpers/GetStaticData"; +import "./ListOfTools.css"; + +const { Search } = Input; + +function ListOfTools() { + const VIEW_OPTIONS = [ + { + value: "grid", + icon: , + }, + { + value: "list", + icon: , + }, + ]; + const [viewType, setViewType] = useState(VIEW_OPTIONS[0].value); + const [isListLoading, setIsListLoading] = useState(false); + const [openAddTool, setOpenAddTool] = useState(false); + const [editItem, setEditItem] = useState(null); + const { sessionDetails } = useSessionStore(); + const { setAlertDetails } = useAlertStore(); + const axiosPrivate = useAxiosPrivate(); + + const [listOfTools, setListOfTools] = useState([]); + const [filteredListOfTools, setFilteredListOfTools] = useState([]); + const [search, setSearch] = useState(""); + + useEffect(() => { + getListOfTools(); + }, []); + + const getListOfTools = () => { + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/ `, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + }, + }; + + setIsListLoading(true); + axiosPrivate(requestOptions) + .then((res) => { + const data = res?.data; + setListOfTools(data); + }) + .catch((err) => { + setAlertDetails( + handleException(err, "Failed to get the list of tools") + ); + }) + .finally(() => { + setIsListLoading(false); + }); + }; + + const handleAddNewTool = (body) => { + let method = "POST"; + let url = `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/`; + const isEdit = editItem && Object.keys(editItem)?.length > 0; + if (isEdit) { + method = "PATCH"; + url += `${editItem?.tool_id}/`; + } + return new Promise((resolve, reject) => { + const requestOptions = { + method, + url, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + "Content-Type": "application/json", + }, + data: body, + }; + + axiosPrivate(requestOptions) + .then((res) => { + const tool = res?.data; + updateList(isEdit, tool); + setOpenAddTool(false); + resolve(true); + }) + .catch((err) => { + reject(err); + }); + }); + }; + + const updateList = (isEdit, data) => { + let tools = [...listOfTools]; + + if (isEdit) { + tools = tools.map((item) => + item?.tool_id === data?.tool_id ? data : item + ); + setEditItem(null); + } else { + tools.push(data); + } + setListOfTools(tools); + }; + + const handleEdit = (event, id) => { + event.domEvent.stopPropagation(); + const editToolData = [...listOfTools].find((item) => item?.tool_id === id); + if (!editToolData) { + return; + } + setEditItem(editToolData); + setOpenAddTool(true); + }; + + const handleDelete = (event, id) => { + const requestOptions = { + method: "DELETE", + url: `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/${id}`, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + }, + }; + + axiosPrivate(requestOptions) + .then(() => { + const tools = [...listOfTools].filter((tool) => tool?.tool_id !== id); + setListOfTools(tools); + }) + .catch((err) => { + setAlertDetails({ + type: "error", + // TODO: Handle with generic function to parse drf-validation error messages + // Here we assume its either a server error or display a generic message + content: err?.response?.data?.errors[0].detail || "Failed to delete", + }); + }); + }; + + const handleViewChange = (type) => { + setViewType(type); + }; + + useEffect(() => { + if (search?.length === 0) { + setFilteredListOfTools(listOfTools); + } + const filteredList = [...listOfTools].filter((tool) => { + const name = tool.tool_name?.toUpperCase(); + const searchUpperCase = search.toUpperCase(); + return name.includes(searchUpperCase); + }); + setFilteredListOfTools(filteredList); + }, [search, listOfTools]); + + const onSearchDebounce = useCallback( + debounce(({ target: { value } }) => { + setSearch(value); + }, 600), + [] + ); + + return ( + <> +
+
+
+
+ + Prompt Studio + +
+ + + } + onClick={() => setOpenAddTool(true)} + > + New Tool + +
+
+
+
+ +
+
+
+
+ + + ); +} + +export { ListOfTools }; diff --git a/frontend/src/components/custom-tools/manage-docs-modal/ManageDocsModal.css b/frontend/src/components/custom-tools/manage-docs-modal/ManageDocsModal.css new file mode 100644 index 000000000..0cfe905dc --- /dev/null +++ b/frontend/src/components/custom-tools/manage-docs-modal/ManageDocsModal.css @@ -0,0 +1,20 @@ +/* Styles for ManageDocsModal */ + +.manage-docs-upload { + background-color: #0000000A; +} + +.manage-docs-items-list { + max-height: 400px; + width: 100%; + overflow-y: auto; +} + +.manage-docs-item { + display: flex; + justify-content: space-between; +} + +.manage-docs-div { + margin: 0; +} \ No newline at end of file diff --git a/frontend/src/components/custom-tools/manage-docs-modal/ManageDocsModal.jsx b/frontend/src/components/custom-tools/manage-docs-modal/ManageDocsModal.jsx new file mode 100644 index 000000000..7630be445 --- /dev/null +++ b/frontend/src/components/custom-tools/manage-docs-modal/ManageDocsModal.jsx @@ -0,0 +1,232 @@ +import { DeleteOutlined, PlusOutlined } from "@ant-design/icons"; +import { + Button, + Divider, + Modal, + Radio, + Table, + Tooltip, + Typography, + Upload, +} from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import { handleException } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useCustomToolStore } from "../../../store/custom-tool-store"; +import { useSessionStore } from "../../../store/session-store"; +import { ConfirmModal } from "../../widgets/confirm-modal/ConfirmModal"; +import { EmptyState } from "../../widgets/empty-state/EmptyState"; +import SpaceWrapper from "../../widgets/space-wrapper/SpaceWrapper"; +import "./ManageDocsModal.css"; + +function ManageDocsModal({ + open, + setOpen, + generateIndex, + handleUpdateTool, + handleDocChange, +}) { + const [isUploading, setIsUploading] = useState(false); + const [rows, setRows] = useState([]); + const { sessionDetails } = useSessionStore(); + const { setAlertDetails } = useAlertStore(); + const { + selectedDoc, + listOfDocs, + updateCustomTool, + details, + defaultLlmProfile, + disableLlmOrDocChange, + } = useCustomToolStore(); + const axiosPrivate = useAxiosPrivate(); + + const columns = [ + { + title: "Document", + dataIndex: "document", + key: "document", + }, + { + title: "", + dataIndex: "delete", + key: "delete", + width: 30, + }, + { + title: "", + dataIndex: "select", + key: "select", + width: 30, + }, + ]; + + useEffect(() => { + const newRows = listOfDocs.map((doc) => { + return { + key: doc, + document: doc || "", + delete: ( + handleDelete(doc)} + content="The document will be permanently deleted." + > + + + ), + select: ( + handleDocChange(doc)} + disabled={disableLlmOrDocChange?.length > 0} + /> + ), + }; + }); + setRows(newRows); + }, [listOfDocs, selectedDoc, disableLlmOrDocChange]); + + const handleUploadChange = (info) => { + if (info.file.status === "uploading") { + setIsUploading(true); + } + + if (info.file.status === "done") { + setIsUploading(false); + setAlertDetails({ + type: "success", + content: "File uploaded successfully", + }); + + const docName = info?.file?.name; + const newListOfDocs = [...listOfDocs]; + newListOfDocs.push(docName); + const body = { + selectedDoc: docName, + listOfDocs: newListOfDocs, + }; + updateCustomTool(body); + handleUpdateTool({ output: docName }); + setOpen(false); + generateIndex(info?.file?.name); + } else if (info.file.status === "error") { + setIsUploading(false); + setAlertDetails({ + type: "error", + content: "Failed to upload", + }); + } + }; + + const handleDelete = (docName) => { + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/file/delete?file_name=${docName}&tool_id=${details?.tool_id}`, + }; + + axiosPrivate(requestOptions) + .then(() => { + const newListOfDocs = [...listOfDocs].filter( + (item) => item !== docName + ); + updateCustomTool({ listOfDocs: newListOfDocs }); + + if (docName === selectedDoc) { + updateCustomTool({ selectedDoc: "" }); + handleUpdateTool({ output: "" }); + } + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to delete")); + }); + }; + + return ( + setOpen(false)} + centered + footer={null} + maskClosable={false} + > +
+ +
+ + Manage Documents + +
+
+ + + + + +
+ + +
+ Uploaded files +
+ {!listOfDocs || listOfDocs?.length === 0 ? ( + + ) : ( +
+ + + )} + + + + + ); +} + +ManageDocsModal.propTypes = { + open: PropTypes.bool.isRequired, + setOpen: PropTypes.func.isRequired, + generateIndex: PropTypes.func.isRequired, + handleUpdateTool: PropTypes.func.isRequired, + handleDocChange: PropTypes.func.isRequired, +}; +export { ManageDocsModal }; diff --git a/frontend/src/components/custom-tools/manage-llm-profiles-modal/ManageLlmProfilesModal.jsx b/frontend/src/components/custom-tools/manage-llm-profiles-modal/ManageLlmProfilesModal.jsx new file mode 100644 index 000000000..b9075562c --- /dev/null +++ b/frontend/src/components/custom-tools/manage-llm-profiles-modal/ManageLlmProfilesModal.jsx @@ -0,0 +1,37 @@ +import { Modal } from "antd"; +import PropTypes from "prop-types"; +import { ManageLlmProfiles } from "../manage-llm-profiles/ManageLlmProfiles"; + +function ManageLlmProfilesModal({ + open, + setOpen, + setOpenLlm, + setEditLlmProfileId, +}) { + return ( + setOpen(false)} + centered + footer={null} + width={800} + maskClosable={false} + > + + + ); +} + +ManageLlmProfilesModal.propTypes = { + open: PropTypes.bool.isRequired, + setOpen: PropTypes.func.isRequired, + setOpenLlm: PropTypes.func.isRequired, + setEditLlmProfileId: PropTypes.func.isRequired, +}; + +export { ManageLlmProfilesModal }; diff --git a/frontend/src/components/custom-tools/manage-llm-profiles/ManageLlmProfiles.css b/frontend/src/components/custom-tools/manage-llm-profiles/ManageLlmProfiles.css new file mode 100644 index 000000000..f4bce61c1 --- /dev/null +++ b/frontend/src/components/custom-tools/manage-llm-profiles/ManageLlmProfiles.css @@ -0,0 +1,5 @@ +/* Styles for ManageLlmProfiles */ + +.manage-llm-pro-icon { + font-size: 10px; +} \ No newline at end of file diff --git a/frontend/src/components/custom-tools/manage-llm-profiles/ManageLlmProfiles.jsx b/frontend/src/components/custom-tools/manage-llm-profiles/ManageLlmProfiles.jsx new file mode 100644 index 000000000..5b294ef1a --- /dev/null +++ b/frontend/src/components/custom-tools/manage-llm-profiles/ManageLlmProfiles.jsx @@ -0,0 +1,207 @@ +import { DeleteOutlined, EditOutlined } from "@ant-design/icons"; +import { Button, Radio, Space, Table, Typography } from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import { handleException } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useCustomToolStore } from "../../../store/custom-tool-store"; +import { useSessionStore } from "../../../store/session-store"; +import { ConfirmModal } from "../../widgets/confirm-modal/ConfirmModal"; +import { CustomButton } from "../../widgets/custom-button/CustomButton"; +import SpaceWrapper from "../../widgets/space-wrapper/SpaceWrapper"; +import "./ManageLlmProfiles.css"; + +const columns = [ + { + title: "Name", + dataIndex: "name", + key: "name", + }, + { + title: "LLM", + dataIndex: "llm", + key: "llm", + }, + { + title: "Embedding Model", + dataIndex: "embedding_model", + key: "embedding_model", + }, + { + title: "Vector Database", + dataIndex: "vector_db", + key: "vector_db", + }, + { + title: "", + dataIndex: "delete", + key: "delete", + width: 30, + }, + { + title: "", + dataIndex: "edit", + key: "edit", + width: 30, + }, + { + title: "Select Default", + dataIndex: "select", + key: "select", + align: "center", + }, +]; +function ManageLlmProfiles({ setOpen, setOpenLlm, setEditLlmProfileId }) { + const [rows, setRows] = useState([]); + const axiosPrivate = useAxiosPrivate(); + const { sessionDetails } = useSessionStore(); + const { details, defaultLlmProfile, updateCustomTool, llmProfiles } = + useCustomToolStore(); + const { setAlertDetails } = useAlertStore(); + + const handleDefaultLlm = (profileId) => { + const body = { + default_profile: profileId, + }; + + const requestOptions = { + method: "PATCH", + url: `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/${details?.tool_id}/`, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + "Content-Type": "application/json", + }, + data: body, + }; + + axiosPrivate(requestOptions) + .then((res) => { + const data = res?.data; + const updatedState = { + defaultLlmProfile: data?.default_profile, + }; + updateCustomTool(updatedState); + setAlertDetails({ + type: "success", + content: "Default LLM Profile updated successfully", + }); + }) + .catch((err) => { + handleException(err, "Failed to set default LLM Profile"); + }); + }; + + useEffect(() => { + const modifiedRows = llmProfiles.map((item, index) => { + return { + key: item?.profile_id, + name: item?.profile_name || "", + llm: item?.llm || "", + embedding_model: item?.embedding_model || "", + vector_db: item?.vector_store || "", + delete: ( + handleDelete(item?.profile_id)} + content="The LLM profile will be permanently deleted." + > + + + ), + edit: ( + + ), + select: ( + handleDefaultLlm(item?.profile_id)} + /> + ), + }; + }); + setRows(modifiedRows); + }, [llmProfiles, defaultLlmProfile]); + + const handleAddNewLlm = () => { + setOpen(false); + setOpenLlm(true); + }; + + const handleEdit = (id) => { + setEditLlmProfileId(id); + handleAddNewLlm(); + }; + + const handleDelete = (id) => { + const requestOptions = { + method: "DELETE", + url: `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/profile-manager/${id}/`, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + }, + }; + + axiosPrivate(requestOptions) + .then(() => { + const modifiedLlmProfiles = [...llmProfiles].filter( + (item) => item?.profile_id !== id + ); + const body = { + llmProfiles: modifiedLlmProfiles, + }; + updateCustomTool(body); + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to delete")); + }); + }; + + return ( +
+
+ +
+ + LLM Profiles Manager + +
+
+
+
+ + + +
+ + + + Add New LLM Profile + + +
+ + ); +} + +ManageLlmProfiles.propTypes = { + setOpen: PropTypes.func.isRequired, + setOpenLlm: PropTypes.func.isRequired, + setEditLlmProfileId: PropTypes.func.isRequired, +}; + +export { ManageLlmProfiles }; diff --git a/frontend/src/components/custom-tools/notes-card/NotesCard.css b/frontend/src/components/custom-tools/notes-card/NotesCard.css new file mode 100644 index 000000000..be4693152 --- /dev/null +++ b/frontend/src/components/custom-tools/notes-card/NotesCard.css @@ -0,0 +1,15 @@ +/* Styles for NotesCard */ + +.tool-ide-notes-card { + border: 1px solid #D9D9D9; + background-color: #E0E5EB; +} + +.tool-ide-notes-card .ant-card-body { + padding: 14px !important; +} + +.tool-ide-notes-card .delete-icon { + font-size: 12px; + color: #575859; +} diff --git a/frontend/src/components/custom-tools/notes-card/NotesCard.jsx b/frontend/src/components/custom-tools/notes-card/NotesCard.jsx new file mode 100644 index 000000000..e4f68cf2f --- /dev/null +++ b/frontend/src/components/custom-tools/notes-card/NotesCard.jsx @@ -0,0 +1,75 @@ +import { DeleteOutlined, EditOutlined } from "@ant-design/icons"; +import { Button, Card, Col, Row, Space, Tooltip } from "antd"; +import PropTypes from "prop-types"; + +import "./NotesCard.css"; +import { EditableText } from "../editable-text/EditableText"; +import { useState } from "react"; +import { ConfirmModal } from "../../widgets/confirm-modal/ConfirmModal"; + +function NotesCard({ details, handleChange, handleDelete }) { + const [isEditingTitle, setIsEditingTitle] = useState(false); + const [isEditingNote, setIsEditingNote] = useState(false); + + const enableEdit = (event) => { + event.stopPropagation(); + setIsEditingTitle(true); + setIsEditingNote(true); + }; + + return ( + + + + + + + + + + + handleDelete(details?.prompt_id)} + content="The note will be permanently deleted." + > + + + + + + + + + + ); +} + +NotesCard.propTypes = { + details: PropTypes.object.isRequired, + handleChange: PropTypes.func.isRequired, + handleDelete: PropTypes.func.isRequired, +}; + +export { NotesCard }; diff --git a/frontend/src/components/custom-tools/output-for-doc-modal/OutputForDocModal.css b/frontend/src/components/custom-tools/output-for-doc-modal/OutputForDocModal.css new file mode 100644 index 000000000..3513d093a --- /dev/null +++ b/frontend/src/components/custom-tools/output-for-doc-modal/OutputForDocModal.css @@ -0,0 +1,18 @@ +/* Styles for OutputForDocModal */ + +.output-doc-layout { + height: 600px; + overflow: hidden; + display: flex; + flex-direction: column; +} + +.output-doc-table { + flex: 1; + overflow-y: auto; +} + +.output-doc-gap { + margin-bottom: 8px; +} + diff --git a/frontend/src/components/custom-tools/output-for-doc-modal/OutputForDocModal.jsx b/frontend/src/components/custom-tools/output-for-doc-modal/OutputForDocModal.jsx new file mode 100644 index 000000000..1bfb89d5d --- /dev/null +++ b/frontend/src/components/custom-tools/output-for-doc-modal/OutputForDocModal.jsx @@ -0,0 +1,134 @@ +import { Button, Modal, Table, Typography } from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import { useCustomToolStore } from "../../../store/custom-tool-store"; +import { useSessionStore } from "../../../store/session-store"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import "./OutputForDocModal.css"; +import { CheckCircleFilled, CloseCircleFilled } from "@ant-design/icons"; + +const columns = [ + { + title: "Document", + dataIndex: "document", + key: "document", + }, + { + title: "Value", + dataIndex: "value", + key: "value", + }, +]; + +function OutputForDocModal({ + open, + setOpen, + promptId, + promptKey, + profileManagerId, +}) { + const [rows, setRows] = useState([]); + const { details, listOfDocs } = useCustomToolStore(); + const { sessionDetails } = useSessionStore(); + const axiosPrivate = useAxiosPrivate(); + useEffect(() => { + handleGetOutputForDocs(); + }, [open]); + + const handleGetOutputForDocs = () => { + if (!profileManagerId) { + setRows([]); + return; + } + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/prompt-output/?tool_id=${details?.tool_id}&prompt_id=${promptId}&profile_manager=${profileManagerId}`, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + }, + }; + + axiosPrivate(requestOptions) + .then((res) => { + const data = res?.data || []; + data.sort((a, b) => { + return new Date(b.created_at) - new Date(a.created_at); + }); + handleRowsGeneration(data); + }) + .catch((err) => { + throw err; + }); + }; + + const handleRowsGeneration = (data) => { + const rowsData = []; + [...listOfDocs].forEach((item) => { + const output = data.find((outputValue) => outputValue?.doc_name === item); + const isSuccess = output?.output?.length > 0; + const content = isSuccess ? output?.output : "Failed"; + + const result = { + key: item, + document: item, + value: ( + + + {isSuccess ? ( + + ) : ( + + )} + {" "} + {content} + + ), + }; + rowsData.push(result); + }); + setRows(rowsData); + }; + + return ( + setOpen(false)} + footer={null} + centered + maskClosable={false} + > +
+
+ + {promptKey} + +
+
+
+ +
+
+
+
+ + + + ); +} + +OutputForDocModal.propTypes = { + open: PropTypes.bool.isRequired, + setOpen: PropTypes.func.isRequired, + promptId: PropTypes.string.isRequired, + promptKey: PropTypes.string.isRequired, + profileManagerId: PropTypes.string.isRequired, +}; + +export { OutputForDocModal }; diff --git a/frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx b/frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx new file mode 100644 index 000000000..5fd9f9201 --- /dev/null +++ b/frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx @@ -0,0 +1,102 @@ +import { Viewer, Worker } from "@react-pdf-viewer/core"; +import { defaultLayoutPlugin } from "@react-pdf-viewer/default-layout"; +import { pageNavigationPlugin } from "@react-pdf-viewer/page-navigation"; +import { Typography } from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import { handleException } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useCustomToolStore } from "../../../store/custom-tool-store"; +import { useSessionStore } from "../../../store/session-store"; +import { EmptyState } from "../../widgets/empty-state/EmptyState"; +import { SpinnerLoader } from "../../widgets/spinner-loader/SpinnerLoader"; + +function PdfViewer({ setOpenManageDocsModal }) { + const [fileUrl, setFileUrl] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const newPlugin = defaultLayoutPlugin(); + const pageNavigationPluginInstance = pageNavigationPlugin(); + const { sessionDetails } = useSessionStore(); + const { setAlertDetails } = useAlertStore(); + const { selectedDoc, details } = useCustomToolStore(); + const axiosPrivate = useAxiosPrivate(); + + const base64toBlob = (data) => { + const bytes = atob(data); + let length = bytes.length; + const out = new Uint8Array(length); + + while (length--) { + out[length] = bytes.charCodeAt(length); + } + + return new Blob([out], { type: "application/pdf" }); + }; + + useEffect(() => { + if (!selectedDoc) { + setFileUrl(""); + return; + } + + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/file/fetch_contents?file_name=${selectedDoc}&tool_id=${details?.tool_id}`, + }; + + setIsLoading(true); + axiosPrivate(requestOptions) + .then((res) => { + const base64String = res?.data?.data || ""; + const blob = base64toBlob(base64String); + setFileUrl(URL.createObjectURL(blob)); + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to load the document")); + }) + .finally(() => { + setIsLoading(false); + }); + }, [selectedDoc]); + + if (isLoading) { + return ; + } + + if (!selectedDoc) { + return ( + setOpenManageDocsModal(true)} + /> + ); + } + + if (!fileUrl) { + return ( +
+ Failed to load the document +
+ ); + } + + return ( +
+ + + +
+ ); +} + +PdfViewer.propTypes = { + setOpenManageDocsModal: PropTypes.func.isRequired, +}; + +export { PdfViewer }; diff --git a/frontend/src/components/custom-tools/pre-and-post-amble-modal/PreAndPostAmbleModal.css b/frontend/src/components/custom-tools/pre-and-post-amble-modal/PreAndPostAmbleModal.css new file mode 100644 index 000000000..c9e15cffb --- /dev/null +++ b/frontend/src/components/custom-tools/pre-and-post-amble-modal/PreAndPostAmbleModal.css @@ -0,0 +1,23 @@ +/* Styles for PreAndPostAmbleModal */ + +.pre-post-amble-modal .ant-modal-content { + padding: 0px; +} + +.pre-post-amble-body { + padding: 20px; +} + +.pre-post-amble-body-space { + width: 100%; +} + +.pre-post-amble-title { + font-size: 16px; +} + +.pre-post-amble-footer { + background-color: #F6F8FB; + border-radius: 0px 0px 10px 10px; + padding: 16px; +} diff --git a/frontend/src/components/custom-tools/pre-and-post-amble-modal/PreAndPostAmbleModal.jsx b/frontend/src/components/custom-tools/pre-and-post-amble-modal/PreAndPostAmbleModal.jsx new file mode 100644 index 000000000..a43130ba7 --- /dev/null +++ b/frontend/src/components/custom-tools/pre-and-post-amble-modal/PreAndPostAmbleModal.jsx @@ -0,0 +1,120 @@ +import { Button, Input, Modal, Space, Typography } from "antd"; +import PropTypes from "prop-types"; + +import { useEffect, useState } from "react"; +import "./PreAndPostAmbleModal.css"; + +import { handleException } from "../../../helpers/GetStaticData"; +import { useAlertStore } from "../../../store/alert-store"; +import { useCustomToolStore } from "../../../store/custom-tool-store"; +import { CustomButton } from "../../widgets/custom-button/CustomButton"; + +const fieldNames = { + preamble: "PREAMBLE", + postamble: "POSTAMBLE", +}; + +function PreAndPostAmbleModal({ isOpen, closeModal, type, handleUpdateTool }) { + const [title, setTitle] = useState(""); + const [text, setText] = useState(""); + const { details, updateCustomTool } = useCustomToolStore(); + const { setAlertDetails } = useAlertStore(); + + useEffect(() => { + if (!isOpen) { + setText(""); + setTitle(""); + return; + } + + if (type === fieldNames.preamble) { + setTitle("Preamble"); + setText(details?.preamble || ""); + return; + } + + if (type === fieldNames.postamble) { + setTitle("Postamble"); + setText(details?.postamble || ""); + } + }, [isOpen]); + + const handleSave = () => { + const body = {}; + if (type === fieldNames.preamble) { + body["preamble"] = text; + } + + if (type === fieldNames.postamble) { + body["postamble"] = text; + } + handleUpdateTool(body) + .then((res) => { + const data = res?.data; + const updatedData = { + preamble: data?.preamble || "", + postamble: data?.postamble || "", + }; + const updatedDetails = { ...details, ...updatedData }; + updateCustomTool({ details: updatedDetails }); + closeModal(); + setAlertDetails({ + type: "success", + content: "Saved successfully", + }); + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to update.")); + }); + }; + + return ( + +
+ +
+ + {title} + +
+
+
+ Add {title} +
+
+
+ setText(e.target.value)} + /> +
+
+
+
+ + + + Save + + +
+
+ ); +} + +PreAndPostAmbleModal.propTypes = { + isOpen: PropTypes.bool.isRequired, + closeModal: PropTypes.func.isRequired, + type: PropTypes.string.isRequired, + handleUpdateTool: PropTypes.func.isRequired, +}; + +export { PreAndPostAmbleModal }; diff --git a/frontend/src/components/custom-tools/prompt-card/PromptCard.css b/frontend/src/components/custom-tools/prompt-card/PromptCard.css new file mode 100644 index 000000000..40ce1bc0e --- /dev/null +++ b/frontend/src/components/custom-tools/prompt-card/PromptCard.css @@ -0,0 +1,111 @@ +/* Styles for PromptCard */ + +.prompt-card { + border: 1px solid #D9D9D9; +} + +.prompt-card .ant-card-body { + padding: 0px !important; +} + +.prompt-card-div { + padding: 12px; +} + +.prompt-card-bg-col1 { + background-color: #ECEFF3; +} + +.prompt-card-rad { + border-radius: 8px 8px 0px 0px; +} + +.prompt-card-head-info-icon { + color: #575859; +} + +.prompt-card-actions-head { + font-size: 12px; + color: #575859; +} + +.prompt-card-head .ant-typography { + margin-bottom: 0px; +} + +.prompt-card-divider { + border-color: #D9D9D9; + margin: 0px 0px; +} + +.prompt-card-paginate { + font-size: 12px; +} + +.prompt-card-llm-profiles { + display: flex; + justify-content: space-between; +} + +.prompt-card-comp-layout { + width: 100%; + padding: 12px; + background-color: #F5F7F9; +} + +.prompt-card-comp-layout-border { + border-radius: 0px 0px 10px 10px; +} + +.prompt-card-actions-dropdowns { + display: flex; +} + +.prompt-card-tags { + padding: 0px 14px; +} + +.prompt-card-result { + padding-top: 12px; + background-color: #FFF8E6; + border-radius: 0px 0px 8px 8px; +} + +.prompt-card-result .ant-typography { + margin-bottom: 0px; +} + +.prompt-card-res { + white-space: pre-wrap; +} + +.prompt-card-select-type { + width: 100px; +} + +.prompt-card-gap { + margin-bottom: 2px; +} + +.assert-p-l-4 { + padding-left: 4px; +} + +.assert-p-r-4 { + padding-right: 4px; +} + +.assertion-comp { + background-color: #ECEFF3; + border-end-end-radius: 0px; + border-end-start-radius: 0px; +} + +.assertion-comp .ant-collapse-header { + display: none !important; + padding: 0 !important; +} + +.assertion-comp .ant-collapse-content-box { + padding: 0px !important; +} \ No newline at end of file diff --git a/frontend/src/components/custom-tools/prompt-card/PromptCard.jsx b/frontend/src/components/custom-tools/prompt-card/PromptCard.jsx new file mode 100644 index 000000000..9e5eebcb5 --- /dev/null +++ b/frontend/src/components/custom-tools/prompt-card/PromptCard.jsx @@ -0,0 +1,839 @@ +import { + ArrowDownOutlined, + CheckCircleOutlined, + DeleteOutlined, + EditOutlined, + LeftOutlined, + PlayCircleOutlined, + RightOutlined, + SearchOutlined, + SyncOutlined, +} from "@ant-design/icons"; +import { + Button, + Card, + Col, + Collapse, + Divider, + Input, + Row, + Select, + Space, + Spin, + Tag, + Tooltip, + Typography, +} from "antd"; +import debounce from "lodash/debounce"; +import PropTypes from "prop-types"; +import { useCallback, useEffect, useRef, useState } from "react"; + +import { AssertionIcon } from "../../../assets"; +import { + handleException, + promptStudioUpdateStatus, +} from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useCustomToolStore } from "../../../store/custom-tool-store"; +import { useSessionStore } from "../../../store/session-store"; +import { ConfirmModal } from "../../widgets/confirm-modal/ConfirmModal"; +import SpaceWrapper from "../../widgets/space-wrapper/SpaceWrapper"; +import { SpinnerLoader } from "../../widgets/spinner-loader/SpinnerLoader"; +import { EditableText } from "../editable-text/EditableText"; +import { EvalMetricTag } from "../eval-metric-tag/EvalMetricTag"; +import { EvalModal } from "../eval-modal/EvalModal"; +import { OutputForDocModal } from "../output-for-doc-modal/OutputForDocModal"; +import "./PromptCard.css"; + +function PromptCard({ + promptDetails, + handleChange, + handleDelete, + updateStatus, +}) { + const [enforceTypeList, setEnforceTypeList] = useState([]); + const [page, setPage] = useState(0); + const [isRunLoading, setIsRunLoading] = useState(false); + const [displayAssertion, setDisplayAssertion] = useState(false); + const [openEval, setOpenEval] = useState(false); + const [isEditingTitle, setIsEditingTitle] = useState(false); + const [isEditingPrompt, setIsEditingPrompt] = useState(false); + const [selectedLlmProfileId, setSelectedLlmProfileId] = useState(null); + const [result, setResult] = useState({ + promptOutputId: null, + output: "", + }); + const [outputIds, setOutputIds] = useState([]); + const [coverage, setCoverage] = useState(0); + const [coverageTotal, setCoverageTotal] = useState(0); + const [isCoverageLoading, setIsCoverageLoading] = useState(false); + const [openOutputForDoc, setOpenOutputForDoc] = useState(false); + const divRef = useRef(null); + const { + getDropdownItems, + llmProfiles, + selectedDoc, + listOfDocs, + evalMetrics, + updateCustomTool, + details, + disableLlmOrDocChange, + } = useCustomToolStore(); + const { sessionDetails } = useSessionStore(); + const { setAlertDetails } = useAlertStore(); + const axiosPrivate = useAxiosPrivate(); + + useEffect(() => { + if (promptDetails?.is_assert) { + setDisplayAssertion(true); + } + const outputTypeData = getDropdownItems("output_type"); + const dropdownList1 = Object.keys(outputTypeData).map((item) => { + return { value: outputTypeData[item] }; + }); + setEnforceTypeList(dropdownList1); + + const llmProfileId = promptDetails?.profile_manager; + if (!llmProfileId) { + setPage(0); + return; + } + const index = llmProfiles.findIndex( + (item) => item?.profile_id === llmProfileId + ); + setPage(index + 1); + }, []); + + useEffect(() => { + setSelectedLlmProfileId(promptDetails?.profile_manager || null); + }, [promptDetails]); + + useEffect(() => { + handleGetOutput(); + handleGetCoverage(); + }, [selectedLlmProfileId, selectedDoc, listOfDocs]); + + useEffect(() => { + let listOfIds = [...disableLlmOrDocChange]; + const promptId = promptDetails?.prompt_id; + const isIncluded = listOfIds.includes(promptId); + + if ( + (isIncluded && isCoverageLoading) || + (!isIncluded && !isCoverageLoading) + ) { + return; + } + + if (isIncluded && !isCoverageLoading) { + listOfIds = listOfIds.filter((item) => item !== promptId); + } + + if (!isIncluded && isCoverageLoading) { + listOfIds.push(promptId); + } + updateCustomTool({ disableLlmOrDocChange: listOfIds }); + }, [isCoverageLoading]); + + useEffect(() => { + if (page < 1) { + return; + } + const llmProfile = llmProfiles[page - 1]; + if (llmProfile?.profile_id !== promptDetails?.profile_id) { + handleChange( + llmProfile?.profile_id, + promptDetails?.prompt_id, + "profile_manager" + ); + } + }, [page]); + + useEffect(() => { + if (displayAssertion !== promptDetails?.is_assert) { + handleChange( + displayAssertion, + promptDetails?.prompt_id, + "is_assert", + true + ); + } + }, [displayAssertion]); + + useEffect(() => { + if (isCoverageLoading && coverageTotal === listOfDocs?.length) { + setIsCoverageLoading(false); + } + }, [coverageTotal]); + + const onSearchDebounce = useCallback( + debounce((event) => { + handleChange(event, promptDetails?.prompt_id, false, true); + }, 1000), + [] + ); + + const isJson = (text) => { + return typeof text === "object"; + }; + + const handlePageLeft = () => { + if (page <= 1) { + return; + } + + const newPage = page - 1; + setPage(newPage); + }; + + const handlePageRight = () => { + if (page >= llmProfiles?.length) { + return; + } + + const newPage = page + 1; + setPage(newPage); + }; + + const sortEvalMetricsByType = (metrics) => { + const sieve = {}; + for (const metric of metrics) { + if (!sieve[metric.type]) { + sieve[metric.type] = [metric]; + } else { + sieve[metric.type].push(metric); + } + } + + let sortedMetrics = []; + for (const type of Object.keys(sieve)) { + sortedMetrics = sortedMetrics.concat(sieve[type]); + } + + return sortedMetrics; + }; + + // Generate the result for the currently selected document + const handleRun = () => { + if (!promptDetails?.prompt_key) { + setAlertDetails({ + type: "error", + content: "Prompt key is not set", + }); + return; + } + + if (!promptDetails?.prompt) { + setAlertDetails({ + type: "error", + content: "Prompt cannot be empty", + }); + return; + } + + if (!promptDetails?.profile_manager?.length) { + setAlertDetails({ + type: "error", + content: "LLM Profile is not selected", + }); + return; + } + + if (!selectedDoc) { + setAlertDetails({ + type: "error", + content: "Document not selected", + }); + return; + } + + setIsRunLoading(true); + setIsCoverageLoading(true); + setCoverage(0); + handleRunApiRequest(selectedDoc) + .then((res) => { + const data = res?.data; + const value = data[promptDetails?.prompt_key]; + let method = "POST"; + let url = `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/prompt-output/`; + if (result?.promptOutputId) { + method = "PATCH"; + url += `${result?.promptOutputId}/`; + } + handleUpdateOutput(value, selectedDoc, method, url); + + if (value?.length > 0) { + setCoverage((prev) => prev + 1); + } else { + setAlertDetails({ + type: "error", + content: `Failed to generate output for ${selectedDoc}`, + }); + } + handleCoverage(); + + const modifiedEvalMetrics = { ...evalMetrics }; + modifiedEvalMetrics[`${promptDetails?.prompt_id}`] = + sortEvalMetricsByType( + data[`${promptDetails?.prompt_key}__evaluation`] || [] + ); + updateCustomTool({ evalMetrics: modifiedEvalMetrics }); + }) + .catch((err) => { + setIsCoverageLoading(false); + setAlertDetails(handleException(err)); + }) + .finally(() => { + setIsRunLoading(false); + }); + }; + + // Get the coverage for all the documents except the one that's currently selected + const handleCoverage = () => { + const listOfDocsToProcess = [...listOfDocs].filter( + (item) => item !== selectedDoc + ); + + if (listOfDocsToProcess?.length === 0) { + setIsCoverageLoading(false); + return; + } + + setCoverageTotal(1); + listOfDocsToProcess.forEach((item) => { + handleRunApiRequest(item) + .then((res) => { + const data = res?.data; + handleCoverageData(data, item); + }) + .catch((err) => { + setAlertDetails( + handleException(err, `Failed to generate output for ${item}`) + ); + }) + .finally(() => { + setCoverageTotal((prev) => prev + 1); + }); + }); + }; + + const handleRunApiRequest = async (doc) => { + const promptId = promptDetails?.prompt_id; + + const body = { + file_name: doc, + id: promptId, + tool_id: details?.tool_id, + }; + + const requestOptions = { + method: "POST", + url: `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/fetch_response/`, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + "Content-Type": "application/json", + }, + data: body, + }; + + return axiosPrivate(requestOptions) + .then((res) => res) + .catch((err) => { + throw err; + }); + }; + + const handleCoverageData = (data, docName) => { + const outputValue = data[promptDetails?.prompt_key]; + let method = "POST"; + let url = `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/prompt-output/`; + const outputId = outputIds.find((output) => output?.docName === docName); + if (outputId?.promptOutputId?.length) { + method = "PATCH"; + url += `${outputId?.promptOutputId}/`; + } + handleUpdateOutput(outputValue, docName, method, url); + + if (outputValue?.length > 0) { + setCoverage((prev) => prev + 1); + } else { + setAlertDetails({ + type: "error", + content: `Failed to generate output for ${docName}`, + }); + } + }; + + const handleUpdateOutput = (outputValue, docName, method, url) => { + const body = { + output: outputValue, + tool_id: details?.tool_id, + prompt_id: promptDetails?.prompt_id, + profile_manager: promptDetails?.profile_manager, + doc_name: docName, + }; + + const requestOptions = { + method, + url, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + "Content-Type": "application/json", + }, + data: body, + }; + + axiosPrivate(requestOptions) + .then((res) => { + if (docName !== selectedDoc) { + return; + } + const data = res?.data; + setResult({ + promptOutputId: data?.prompt_output_id || null, + output: data?.output || "", + }); + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to persist the result")); + }); + }; + + const handleGetOutput = () => { + if (!selectedDoc || !selectedLlmProfileId) { + setResult({ + promptOutputId: null, + output: "", + }); + return; + } + + setIsRunLoading(true); + handleOutputApiRequest(true) + .then((res) => { + const data = res?.data; + + if (!data || data?.length === 0) { + setResult({ + promptOutputId: null, + output: "", + }); + return; + } + + const outputResult = data[0]; + setResult({ + promptOutputId: outputResult?.prompt_output_id, + output: outputResult?.output || "", + }); + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to generate the output")); + }) + .finally(() => { + setIsRunLoading(false); + }); + }; + + const handleGetCoverage = () => { + if (!selectedLlmProfileId) { + return; + } + + setCoverage(0); + handleOutputApiRequest() + .then((res) => { + const data = res?.data; + data.sort((a, b) => { + return new Date(b.created_at) - new Date(a.created_at); + }); + handleGetCoverageData(data); + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to generate result")); + }); + }; + + const handleOutputApiRequest = async (isOutput) => { + let url = `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/prompt-output/?tool_id=${details?.tool_id}&prompt_id=${promptDetails?.prompt_id}&profile_manager=${selectedLlmProfileId}`; + + if (isOutput) { + url += `&doc_name=${selectedDoc}`; + } + const requestOptions = { + method: "GET", + url, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + }, + }; + + return axiosPrivate(requestOptions) + .then((res) => res) + .catch((err) => { + throw err; + }); + }; + + const handleGetCoverageData = (data) => { + const ids = []; + data.forEach((item) => { + const isOutputAdded = ids.findIndex( + (output) => output?.docName === item?.doc_name + ); + + if (isOutputAdded > -1) { + return; + } + + if ( + item?.output?.length > 0 && + [...listOfDocs].includes(item?.doc_name) + ) { + ids.push({ + promptOutputId: item?.prompt_output_id, + docName: item?.doc_name, + }); + } + }); + setOutputIds(ids); + setCoverage(ids?.length); + }; + + const enableEdit = (event) => { + event.stopPropagation(); + setIsEditingTitle(true); + setIsEditingPrompt(true); + }; + + return ( + <> + + + + +
+ + Missing Context Prompt + +
+ + +
+ + False + +
+ + +
+ + True + +
+ + + The below prompt will be executed. + + + + + + + + <> + {displayAssertion && } +
+ + +
+ + + + {updateStatus?.promptId === promptDetails?.prompt_id && ( + <> + {updateStatus?.status === + promptStudioUpdateStatus.isUpdating && ( + } + color="processing" + className="display-flex-align-center" + > + Updating + + )} + {updateStatus?.status === + promptStudioUpdateStatus.done && ( + } + color="success" + className="display-flex-align-center" + > + Done + + )} + + )} + + + + + + + + + + handleDelete(promptDetails?.prompt_id)} + content="The prompt will be permanently deleted." + > + + + + + + + + + + + <> + + 0) && + "prompt-card-comp-layout-border" + }`} + > +
+ +
+ +
+ +
+
+
, + spinning: isTableLoading, + }} + /> + + {deploymentsStaticContent[type].isLogsRequired && ( + <> +
+ + + )} +
+ + ); +} + +Body.propTypes = { + type: PropTypes.string.isRequired, + columns: PropTypes.array.isRequired, + tableData: PropTypes.array.isRequired, + isTableLoading: PropTypes.bool.isRequired, + openAddModal: PropTypes.func.isRequired, +}; + +export { Body }; diff --git a/frontend/src/components/deployments/create-api-deployment-modal/CreateApiDeploymentModal.jsx b/frontend/src/components/deployments/create-api-deployment-modal/CreateApiDeploymentModal.jsx new file mode 100644 index 000000000..6d4526a07 --- /dev/null +++ b/frontend/src/components/deployments/create-api-deployment-modal/CreateApiDeploymentModal.jsx @@ -0,0 +1,250 @@ +import { Form, Input, Modal, Select } from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import { handleException } from "../../../helpers/GetStaticData.js"; +import { useAlertStore } from "../../../store/alert-store"; +import { apiDeploymentsService } from "../../deployments/api-deployment/api-deployments-service.js"; + +const defaultFromDetails = { + display_name: "", + description: "", + api_name: "", + workflow: "", +}; + +const CreateApiDeploymentModal = ({ + open, + setOpen, + setTableData, + isEdit, + selectedRow = {}, + openCodeModal, + setSelectedRow, + workflowId, + workflowEndpointList, +}) => { + const apiDeploymentsApiService = apiDeploymentsService(); + const { setAlertDetails } = useAlertStore(); + + const { Option } = Select; + const [formDetails, setFormDetails] = useState( + isEdit ? { ...selectedRow } : { ...defaultFromDetails } + ); + const [isLoading, setIsLoading] = useState(false); + const [form] = Form.useForm(); + const [backendErrors, setBackendErrors] = useState(null); + const [isFormChanged, setIsFormChanged] = useState(false); + + const getBackendErrorDetail = (attr) => { + if (backendErrors) { + const error = backendErrors?.errors.find((error) => error?.attr === attr); + return error ? error?.detail : null; + } + return null; + }; + + const handleInputChange = (changedValues, allValues) => { + setIsFormChanged(true); + setFormDetails({ ...formDetails, ...allValues }); + const changedFieldName = Object.keys(changedValues)[0]; + form.setFields([ + { + name: changedFieldName, + errors: [], + }, + ]); + setBackendErrors((prevErrors) => { + if (prevErrors) { + const updatedErrors = prevErrors.errors.filter( + (error) => error.attr !== changedFieldName + ); + return { ...prevErrors, errors: updatedErrors }; + } + return null; + }); + }; + + useEffect(() => { + if (workflowId) { + setFormDetails((prevState) => ({ + ...prevState, + workflow: workflowId, + })); + } + }, [workflowId]); + + const clearFormDetails = () => { + setFormDetails({ ...defaultFromDetails }); + }; + + const handleCancel = () => { + setOpen(false); + }; + + const updateTableData = () => { + apiDeploymentsApiService + .getApiDeploymentsList() + .then((res) => { + setTableData(res?.data); + }) + .catch((err) => { + setAlertDetails({ + type: "error", + content: "Error fetching API deployments", + }); + }); + }; + + const createApiDeployment = () => { + setIsLoading(true); + const body = formDetails; + apiDeploymentsApiService + .createApiDeployment(body) + .then((res) => { + if (!workflowId) { + updateTableData(); + setSelectedRow(res?.data); + openCodeModal(true); + } + setOpen(false); + clearFormDetails(); + setAlertDetails({ + type: "success", + content: "New API created successfully", + }); + }) + .catch((err) => { + setAlertDetails(handleException(err)); + }) + .finally(() => { + setIsLoading(false); + }); + }; + + const updateApiDeployment = () => { + setIsLoading(true); + const body = formDetails; + + apiDeploymentsApiService + .updateApiDeployment(body) + .then((res) => { + updateTableData(); + setOpen(false); + clearFormDetails(); + setAlertDetails({ + type: "success", + content: "API deployment updated successfully", + }); + }) + .catch((err) => { + setAlertDetails(handleException(err)); + }) + .finally(() => { + setIsLoading(false); + }); + }; + + return ( + +
+ + + + + + + + + + + + + {!workflowId && ( + + + + )} + +
+ ); +}; + +CreateApiDeploymentModal.propTypes = { + open: PropTypes.bool.isRequired, + setOpen: PropTypes.func.isRequired, + setTableData: PropTypes.func, + isEdit: PropTypes.bool, + selectedRow: PropTypes.object, + openCodeModal: PropTypes.func, + setSelectedRow: PropTypes.func, + workflowId: PropTypes.string, + workflowEndpointList: PropTypes.object, +}; + +export { CreateApiDeploymentModal }; diff --git a/frontend/src/components/deployments/delete-modal/DeleteModal.jsx b/frontend/src/components/deployments/delete-modal/DeleteModal.jsx new file mode 100644 index 000000000..d852bfaf6 --- /dev/null +++ b/frontend/src/components/deployments/delete-modal/DeleteModal.jsx @@ -0,0 +1,24 @@ +import { Modal } from "antd"; +import PropTypes from "prop-types"; + +const DeleteModal = ({ open, setOpen, deleteRecord }) => { + return ( + setOpen(false)} + okText="Delete" + width={500} + > + ); +}; + +DeleteModal.propTypes = { + open: PropTypes.bool.isRequired, + setOpen: PropTypes.func.isRequired, + deleteRecord: PropTypes.func.isRequired, +}; + +export { DeleteModal }; diff --git a/frontend/src/components/deployments/display-code/CodeSnippet.css b/frontend/src/components/deployments/display-code/CodeSnippet.css new file mode 100644 index 000000000..7c1eff0e9 --- /dev/null +++ b/frontend/src/components/deployments/display-code/CodeSnippet.css @@ -0,0 +1,5 @@ +.codeSnippet { + height: 300px; + border: 1px solid #ECEFF3; + overflow-y: auto; +} diff --git a/frontend/src/components/deployments/display-code/CodeSnippet.jsx b/frontend/src/components/deployments/display-code/CodeSnippet.jsx new file mode 100644 index 000000000..3e4c56e59 --- /dev/null +++ b/frontend/src/components/deployments/display-code/CodeSnippet.jsx @@ -0,0 +1,23 @@ +import Prism from "prismjs"; +import "prismjs/themes/prism.css"; +import PropTypes from "prop-types"; +import { useEffect } from "react"; + +import "./CodeSnippet.css"; + +const CodeSnippet = ({ code }) => { + useEffect(() => { + Prism.highlightAll(); + }, [code]); + return ( +
+      {code}
+    
+ ); +}; + +CodeSnippet.propTypes = { + code: PropTypes.string.isRequired, +}; + +export default CodeSnippet; diff --git a/frontend/src/components/deployments/display-code/DisplayCode.css b/frontend/src/components/deployments/display-code/DisplayCode.css new file mode 100644 index 000000000..043663028 --- /dev/null +++ b/frontend/src/components/deployments/display-code/DisplayCode.css @@ -0,0 +1,15 @@ +.codeActions .copyCodeBtn { + background: transparent; + border: none; + cursor: pointer; + font-size: 1.3em; +} + +.codeActions .copyCodeBtn:hover { + background: fixed; +} + +.codeActions .codeLanguage { + width: 150px; + margin-right: 10px; +} diff --git a/frontend/src/components/deployments/display-code/DisplayCode.jsx b/frontend/src/components/deployments/display-code/DisplayCode.jsx new file mode 100644 index 000000000..c4ba1edad --- /dev/null +++ b/frontend/src/components/deployments/display-code/DisplayCode.jsx @@ -0,0 +1,193 @@ +import { CheckCircleOutlined, CopyOutlined } from "@ant-design/icons"; +import { Modal, Select, Tabs, Tooltip } from "antd"; +import Handlebars from "handlebars"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import CodeSnippet from "./CodeSnippet.jsx"; +import "./DisplayCode.css"; + +const DisplayCode = ({ isDialogOpen, setDialogOpen, url }) => { + const handleCloseDialog = () => { + setDialogOpen(false); + }; + const [copied, setCopied] = useState(false); + const [language, setLanguage] = useState("python"); + const [code, setCode] = useState(""); + const [activeTabKey, setActiveTabKey] = useState("POST"); + + useEffect(() => { + generateCode(); + }, [url, language, activeTabKey]); + + const generateCode = () => { + if (language === "python") { + generatePythonCode(); + } else if (language === "bash") { + generateCurlCode(); + } else if (language === "javascript") { + generateJavascriptCode(); + } else { + setCode(""); + } + }; + + const trimIndent = (text) => { + return text + .split("\n") + .map((line) => line.trim()) + .join("\n"); + }; + + const generatePythonCode = () => { + let code = `import requests + api_url = '{{url}}' + headers = { + 'Authorization': 'Bearer REPLACE_WITH_API_KEY' + } + {{#if isPost}} + payload = {'timeout': '80'} + filepath = '/path/to/file' + files=[('file',('file',open(filepath,'rb'),'application/octet-stream'))] + response = requests.request("POST", api_url, headers=headers, data=payload, files=files) + {{else}} + response = requests.request("GET", api_url, headers=headers, data=payload) + {{/if}} + print('Response:', response.json()) + `; + code = trimIndent(code); + const template = Handlebars.compile(code); + + const pythonCode = template({ url, isPost: activeTabKey === "POST" }); + setCode(pythonCode); + }; + + const generateCurlCode = () => { + let code = `curl --location '{{url}}' + --header 'Authorization: Bearer REPLACE_WITH_API_KEY' + {{#if isPost}}--form 'files=@"{{pathToFile}}"' --form 'timeout="80"'{{/if}} + `; + code = trimIndent(code); + const template = Handlebars.compile(code); + const curlCode = template({ + url, + isPost: activeTabKey === "POST", + pathToFile: "/path/to/file", + }); + setCode(curlCode); + }; + + const generateJavascriptCode = () => { + let code = `var myHeaders = new Headers(); + myHeaders.append("Authorization", "Bearer REPLACE_WITH_API_KEY"); + {{#if isPost}} + var formdata = new FormData(); + formdata.append("files", fileInput.files[0], "file"); + formdata.append("timeout", "80"); + var requestOptions = { method: 'POST', body: formdata, redirect: 'follow', headers: myHeaders }; + {{else}} + var requestOptions = { method: 'GET', redirect: 'follow', headers: myHeaders}; + {{/if}} + fetch("{{url}}", requestOptions) + .then(response => response.text()) + .then(result => console.log(result)) + .catch(error => console.log('error', error)); + `; + code = trimIndent(code); + const template = Handlebars.compile(code); + + const jsCode = template({ url, isPost: activeTabKey === "POST" }); + setCode(jsCode); + }; + + const handleCopyClick = () => { + navigator.clipboard.writeText(code); + setCopied(true); + setTimeout(() => setCopied(false), 1500); + }; + + const handleTabKey = (key) => { + setActiveTabKey(key.toString()); + }; + + const onChangeHandler = (value) => { + setLanguage(value); + }; + + const TAB_ITEMS = [ + { + key: "POST", + label: "POST", + children: , + }, + { + key: "GET", + label: "GET", + children: , + }, + ]; + + const LANGUAGE_OPTIONS = [ + { + value: "python", + label: "Python", + }, + { + value: "bash", + label: "cURL", + }, + { + value: "javascript", + label: "JavaScript", + }, + ]; + + return ( + + +
, + spinning: isTableLoading, + }} + pagination={{ defaultPageSize: 5 }} + /> + + + {(isNewKey || isEditKey) && ( + + + Description + onChangeHandler("description", e.target.value)} + value={formDetails.description || ""} + > + + + )} + {openDeleteModal && ( + + )} + + ); +}; + +ManageKeys.propTypes = { + isDialogOpen: PropTypes.bool.isRequired, + setDialogOpen: PropTypes.func.isRequired, + apiKeys: PropTypes.array.isRequired, + setApiKeys: PropTypes.func.isRequired, + selectedApiRow: PropTypes.object.isRequired, +}; + +export { ManageKeys }; diff --git a/frontend/src/components/error/GenericError/GenericError.jsx b/frontend/src/components/error/GenericError/GenericError.jsx new file mode 100644 index 000000000..52e748fb0 --- /dev/null +++ b/frontend/src/components/error/GenericError/GenericError.jsx @@ -0,0 +1,59 @@ +import { Result } from "antd"; +import { useEffect, useState } from "react"; +import { useSearchParams } from "react-router-dom"; + +function GenericError() { + const [searchParams] = useSearchParams(); + const [messages, setMessages] = useState({}); + const [id, setId] = useState(null); + useEffect(() => { + // Simulating fetching JSON data with key-value pairs + const jsonData = { + IDM: { + title: "Sorry, but this invitation is not meant for you.", + subtitle: + "Please contact the organization owner to send you another invite.", + }, + INF: { + title: "This invitation is either invalid or has expired.", + subtitle: + "Please contact the organization owner to send you another invite.", + }, + UMM: { + title: "Sorry, but you seem to be a member of multiple organizations.", + subtitle: "This is not allowed normally. Please contact support.", + }, + USF: { + title: `We're unable to create your account since an account for your organization ${searchParams.get( + "domain" + )} already exists.`, + subtitle: + "You'll need to contact the admin of your organization's account to get access or you'll need to use a different email address to sign up.", + }, + + // Add more key-value pairs as needed + }; + const msgId = searchParams.get("code"); + + setId(msgId); + setMessages(jsonData); + }, []); + + return ( + + ); +} + +export { GenericError }; diff --git a/frontend/src/components/error/NotFound/NotFound.css b/frontend/src/components/error/NotFound/NotFound.css new file mode 100644 index 000000000..7ae8bf161 --- /dev/null +++ b/frontend/src/components/error/NotFound/NotFound.css @@ -0,0 +1 @@ +/* Styles for Not Found */ \ No newline at end of file diff --git a/frontend/src/components/error/NotFound/NotFound.jsx b/frontend/src/components/error/NotFound/NotFound.jsx new file mode 100644 index 000000000..f70e1904b --- /dev/null +++ b/frontend/src/components/error/NotFound/NotFound.jsx @@ -0,0 +1,20 @@ +import { Button, Result } from "antd"; +import { useNavigate } from "react-router-dom"; + +function NotFound() { + const navigate = useNavigate(); + return ( + navigate(-1)}> + Go Back + + } + /> + ); +} + +export { NotFound }; diff --git a/frontend/src/components/error/UnAuthorized/Unauthorized.css b/frontend/src/components/error/UnAuthorized/Unauthorized.css new file mode 100644 index 000000000..bb1b7cdaf --- /dev/null +++ b/frontend/src/components/error/UnAuthorized/Unauthorized.css @@ -0,0 +1,9 @@ +.unauth-container{ + text-align: center; + padding: 20px; +} + +.unauth-text{ + color:#666; + font-size: 24px; +} \ No newline at end of file diff --git a/frontend/src/components/error/UnAuthorized/Unauthorized.jsx b/frontend/src/components/error/UnAuthorized/Unauthorized.jsx new file mode 100644 index 000000000..1eb60d326 --- /dev/null +++ b/frontend/src/components/error/UnAuthorized/Unauthorized.jsx @@ -0,0 +1,19 @@ +import { Typography } from "antd"; + +import { IslandLayout } from "../../../layouts/island-layout/IslandLayout.jsx"; +import "./Unauthorized.css"; + +function Unauthorized() { + return ( + +
+ + Sorry, you dont have access to this page. Please contact the + administrator for assistance. + +
+
+ ); +} + +export { Unauthorized }; diff --git a/frontend/src/components/helpers/auth/PersistentLogin.js b/frontend/src/components/helpers/auth/PersistentLogin.js new file mode 100644 index 000000000..3d89bc4df --- /dev/null +++ b/frontend/src/components/helpers/auth/PersistentLogin.js @@ -0,0 +1,39 @@ +import { useEffect, useState } from "react"; +import { Outlet } from "react-router-dom"; + +import { Logo64 } from "../../../assets"; +import useSessionValid from "../../../hooks/useSessionValid"; +import { useSessionStore } from "../../../store/session-store"; + +function PersistentLogin() { + const [isLoading, setIsLoading] = useState(true); + const { sessionDetails } = useSessionStore(); + const checkSessionValidity = useSessionValid(); + + useEffect(() => { + let isMounted = true; + + const verifySession = async () => { + try { + await checkSessionValidity(); + } finally { + isMounted && setIsLoading(false); + } + }; + + !sessionDetails?.isLoggedIn ? verifySession() : setIsLoading(false); + + return () => (isMounted = false); + }, []); + + if (isLoading) { + return ( +
+ +
+ ); + } + return ; +} + +export { PersistentLogin }; diff --git a/frontend/src/components/helpers/auth/RequireAdmin.js b/frontend/src/components/helpers/auth/RequireAdmin.js new file mode 100644 index 000000000..949bc49fc --- /dev/null +++ b/frontend/src/components/helpers/auth/RequireAdmin.js @@ -0,0 +1,23 @@ +import { Outlet } from "react-router-dom"; + +import { useSessionStore } from "../../../store/session-store"; +import { Unauthorized } from "../../error/UnAuthorized/Unauthorized.jsx"; +import { NotFound } from "../../error/NotFound/NotFound.jsx"; + +const RequireAdmin = () => { + const { sessionDetails } = useSessionStore(); + const isAdmin = sessionDetails?.isAdmin; + const orgName = sessionDetails?.orgName; + const isOpenSource = orgName === "mock_org"; + + if (!isAdmin) { + return ; + } + if (isOpenSource) { + return ; + } + + return ; +}; + +export { RequireAdmin }; diff --git a/frontend/src/components/helpers/auth/RequireAuth.js b/frontend/src/components/helpers/auth/RequireAuth.js new file mode 100644 index 000000000..584884cf8 --- /dev/null +++ b/frontend/src/components/helpers/auth/RequireAuth.js @@ -0,0 +1,25 @@ +import { Navigate, Outlet, useLocation } from "react-router-dom"; + +import { getOrgNameFromPathname } from "../../../helpers/GetStaticData"; +import { useSessionStore } from "../../../store/session-store"; + +const RequireAuth = () => { + const { sessionDetails } = useSessionStore(); + const location = useLocation(); + const isLoggedIn = sessionDetails?.isLoggedIn; + const orgName = sessionDetails?.orgName; + const pathname = location?.pathname; + const currOrgName = getOrgNameFromPathname(pathname); + + if (!isLoggedIn) { + return ; + } + + if (currOrgName !== orgName) { + return ; + } + + return ; +}; + +export { RequireAuth }; diff --git a/frontend/src/components/helpers/auth/RequireGuest.js b/frontend/src/components/helpers/auth/RequireGuest.js new file mode 100644 index 000000000..71bc242d9 --- /dev/null +++ b/frontend/src/components/helpers/auth/RequireGuest.js @@ -0,0 +1,18 @@ +import { Navigate, Outlet, useLocation } from "react-router-dom"; + +import { publicRoutes } from "../../../helpers/GetStaticData"; +import { useSessionStore } from "../../../store/session-store"; + +const RequireGuest = () => { + const { sessionDetails } = useSessionStore(); + const location = useLocation(); + const pathname = location.pathname; + + return !sessionDetails?.isLoggedIn && publicRoutes.includes(pathname) ? ( + + ) : ( + + ); +}; + +export { RequireGuest }; diff --git a/frontend/src/components/helpers/custom-tools/CustomToolsHelper.js b/frontend/src/components/helpers/custom-tools/CustomToolsHelper.js new file mode 100644 index 000000000..8f5f1dd92 --- /dev/null +++ b/frontend/src/components/helpers/custom-tools/CustomToolsHelper.js @@ -0,0 +1,105 @@ +import { useEffect, useState } from "react"; +import { Outlet, useNavigate, useParams } from "react-router-dom"; + +import { handleException } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useCustomToolStore } from "../../../store/custom-tool-store"; +import { useSessionStore } from "../../../store/session-store"; +import { SpinnerLoader } from "../../widgets/spinner-loader/SpinnerLoader"; +import { SocketMessages } from "../socket-messages/SocketMessages"; + +function CustomToolsHelper() { + const [isLoading, setIsLoading] = useState(true); + const [logId, setLogId] = useState(null); + const { id } = useParams(); + const { sessionDetails } = useSessionStore(); + const { updateCustomTool } = useCustomToolStore(); + const { setAlertDetails } = useAlertStore(); + const navigate = useNavigate(); + const axiosPrivate = useAxiosPrivate(); + + useEffect(() => { + const updatedCusTool = { + listOfDocs: [], + details: {}, + defaultLlmProfile: "", + llmProfiles: [], + selectedDoc: null, + }; + + const reqOpsPromptStudio = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/${id}`, + }; + + setIsLoading(true); + handleApiRequest(reqOpsPromptStudio) + .then((res) => { + const data = res?.data; + updatedCusTool["defaultLlmProfile"] = data?.default_profile; + updatedCusTool["details"] = data; + updatedCusTool["selectedDoc"] = data?.output; + setLogId(data?.log_id); + + const reqOpsDocs = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/file?tool_id=${data?.tool_id}`, + }; + return handleApiRequest(reqOpsDocs); + }) + .then((res) => { + const data = res?.data?.map((item) => item?.name); + updatedCusTool["listOfDocs"] = data; + + const reqOpsDropdownItems = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/select_choices`, + }; + return handleApiRequest(reqOpsDropdownItems); + }) + .then((res) => { + const data = res?.data; + updatedCusTool["dropdownItems"] = data; + + const reqOpsLlmProfiles = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/prompt-studio/profile-manager/`, + }; + + return handleApiRequest(reqOpsLlmProfiles); + }) + .then((res) => { + const data = res?.data; + updatedCusTool["llmProfiles"] = data; + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to load the custom tool")); + navigate(`/${sessionDetails?.orgName}/tools`); + }) + .finally(() => { + updateCustomTool(updatedCusTool); + setIsLoading(false); + }); + }, [id]); + + const handleApiRequest = async (requestOptions) => { + return axiosPrivate(requestOptions) + .then((res) => res) + .catch((err) => { + throw err; + }); + }; + + if (isLoading) { + return ; + } + return ( + <> + + + + ); +} + +export { CustomToolsHelper }; diff --git a/frontend/src/components/helpers/project/ProjectHelper.js b/frontend/src/components/helpers/project/ProjectHelper.js new file mode 100644 index 000000000..f55aafef0 --- /dev/null +++ b/frontend/src/components/helpers/project/ProjectHelper.js @@ -0,0 +1,75 @@ +import { useEffect, useState } from "react"; +import { Outlet, useNavigate, useParams } from "react-router-dom"; + +import { + handleException, + workflowStatus, +} from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { MenuLayout } from "../../../layouts/menu-layout/MenuLayout"; +import { useAlertStore } from "../../../store/alert-store"; +import { useSessionStore } from "../../../store/session-store"; +import { useToolSettingsStore } from "../../../store/tool-settings"; +import { useWorkflowStore } from "../../../store/workflow-store"; +import { SpinnerLoader } from "../../widgets/spinner-loader/SpinnerLoader.jsx"; + +function ProjectHelper() { + const { id } = useParams(); + const { sessionDetails } = useSessionStore(); + const { updateWorkflow, setDefaultWorkflowState } = useWorkflowStore(); + const { cleanUpToolSettings } = useToolSettingsStore(); + const { setAlertDetails } = useAlertStore(); + const axiosPrivate = useAxiosPrivate(); + const [isWfLoading, setWfLoading] = useState(true); + const navigate = useNavigate(); + + useEffect(() => { + return () => { + cleanUpToolSettings(); + setDefaultWorkflowState(); + }; + }, []); + + useEffect(() => { + const workflowState = { + projectId: id, + isLoading: false, + }; + updateWorkflow(workflowState); + + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${sessionDetails?.orgId}/workflow/${id}/`, + }; + setWfLoading(true); + axiosPrivate(requestOptions) + .then((res) => { + const data = res?.data; + workflowState["prompt"] = data?.prompt_text; + workflowState["details"] = data; + workflowState["status"] = workflowStatus.generated; + workflowState["isLoading"] = false; + workflowState["projectName"] = data.workflow_name; + updateWorkflow(workflowState); + }) + .catch((err) => { + setAlertDetails(handleException(err, "Failed to load the workflow")); + navigate(`/${sessionDetails?.orgName}/workflows`); + }) + .finally(() => { + setWfLoading(false); + }); + }, [id]); + + if (isWfLoading) { + return ; + } + + return ( + + + + ); +} + +export { ProjectHelper }; diff --git a/frontend/src/components/helpers/socket-messages/SocketMessages.js b/frontend/src/components/helpers/socket-messages/SocketMessages.js new file mode 100644 index 000000000..b0ad3ab36 --- /dev/null +++ b/frontend/src/components/helpers/socket-messages/SocketMessages.js @@ -0,0 +1,66 @@ +import PropTypes from "prop-types"; +import { useContext, useEffect } from "react"; + +import { handleException } from "../../../helpers/GetStaticData"; +import { SocketContext } from "../../../helpers/SocketContext"; +import { useAlertStore } from "../../../store/alert-store"; +import { useSocketLogsStore } from "../../../store/socket-logs-store"; +import { useSocketMessagesStore } from "../../../store/socket-messages-store"; +function SocketMessages({ logId }) { + const { + pushStagedMessage, + updateMessage, + stagedMessages, + pointer, + setPointer, + } = useSocketMessagesStore(); + const { pushLogMessages } = useSocketLogsStore(); + const socket = useContext(SocketContext); + const { setAlertDetails } = useAlertStore(); + + const onMessage = (data) => { + try { + const msg = JSON.parse(new TextDecoder().decode(data.data)); + if (msg?.type === "LOG" || msg?.type === "COST") { + msg.message = msg?.log; + pushLogMessages(msg); + } + if (msg?.type === "UPDATE") { + pushStagedMessage(msg); + } + } catch (err) { + setAlertDetails(handleException(err, "Failed to process socket message")); + } + }; + + useEffect(() => { + if (!logId) { + return; + } + const logMessageChannel = `logs:${logId}`; + socket.on(logMessageChannel, onMessage); + + return () => { + // unsubscribe to the channel to stop listening the socket messages for the logId + socket.off(logMessageChannel); + }; + }, [logId]); + + useEffect(() => { + if (pointer > stagedMessages?.length - 1) { + return; + } + + const stagedMsg = stagedMessages[pointer]; + setTimeout(() => { + updateMessage(stagedMsg); + setPointer(pointer + 1); + }, 0); + }, [stagedMessages, pointer]); +} + +SocketMessages.propTypes = { + logId: PropTypes.string, +}; + +export { SocketMessages }; diff --git a/frontend/src/components/input-output/add-source-modal/AddSourceModa.css b/frontend/src/components/input-output/add-source-modal/AddSourceModa.css new file mode 100644 index 000000000..821ca70f0 --- /dev/null +++ b/frontend/src/components/input-output/add-source-modal/AddSourceModa.css @@ -0,0 +1 @@ +/* Styles for AddSourceModal */ \ No newline at end of file diff --git a/frontend/src/components/input-output/add-source-modal/AddSourceModal.jsx b/frontend/src/components/input-output/add-source-modal/AddSourceModal.jsx new file mode 100644 index 000000000..b896bd257 --- /dev/null +++ b/frontend/src/components/input-output/add-source-modal/AddSourceModal.jsx @@ -0,0 +1,124 @@ +import { Modal } from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import { handleException, sourceTypes } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useSessionStore } from "../../../store/session-store"; +import { AddSource } from "../add-source/AddSource"; +import { ListOfSources } from "../list-of-sources/ListOfSources"; + +function AddSourceModal({ + open, + setOpen, + type, + addNewItem, + editItemId, + setEditItemId, +}) { + const [selectedSourceId, setSelectedSourceId] = useState(null); + const [metadata, setMetadata] = useState({}); + const [titles, setTitles] = useState({}); + const { sessionDetails } = useSessionStore(); + const { setAlertDetails } = useAlertStore(); + const axiosPrivate = useAxiosPrivate(); + + useEffect(() => { + const addOrEdit = editItemId?.length ? "Edit" : "Add"; + setTitles({ + input: addOrEdit + " Data Source", + output: addOrEdit + " Data Destination", + llm: addOrEdit + " LLM", + vector_db: addOrEdit + " Vector DB", + embedding: addOrEdit + " Embedding", + }); + + if (editItemId?.length) { + getSourceDetails(); + } + }, [editItemId]); + + useEffect(() => { + if (!open) { + setTimeout(() => { + // A delay added in order to avoid glitch in the UI when the modal is closed. + setSelectedSourceId(null); + setEditItemId(null); + }, 500); + } + }, [open]); + + const getSourceDetails = () => { + setOpen(true); + + const isConnector = sourceTypes.connectors.includes(type); + let url = `/api/v1/unstract/${sessionDetails?.orgId}`; + if (isConnector) { + url += `/connector/${editItemId}/`; + } else { + url += `/adapter/${editItemId}/`; + } + + const requestOptions = { + method: "GET", + url, + }; + + axiosPrivate(requestOptions) + .then((res) => { + const data = res?.data; + if (isConnector) { + setSelectedSourceId(data?.connector_id); + const connectorMetadata = data?.connector_metadata; + connectorMetadata["connectorName"] = data?.connector_name; + setMetadata(connectorMetadata); + } else { + setSelectedSourceId(data?.adapter_id); + const adapterMetadata = data?.adapter_metadata; + adapterMetadata["adapter_name"] = data?.adapter_name; + setMetadata(adapterMetadata); + } + }) + .catch((err) => { + setAlertDetails(handleException(err)); + }); + }; + + return ( + setOpen(false)} + maskClosable={false} + title={titles[type]} + width={selectedSourceId?.length ? 500 : 1100} + centered + footer={null} + closable={true} + > + {selectedSourceId ? ( + + ) : ( + + )} + + ); +} + +AddSourceModal.propTypes = { + open: PropTypes.bool.isRequired, + setOpen: PropTypes.func.isRequired, + type: PropTypes.string.isRequired, + addNewItem: PropTypes.func.isRequired, + editItemId: PropTypes.string, + setEditItemId: PropTypes.func.isRequired, +}; + +export { AddSourceModal }; diff --git a/frontend/src/components/input-output/add-source/AddSource.css b/frontend/src/components/input-output/add-source/AddSource.css new file mode 100644 index 000000000..7db2c56b1 --- /dev/null +++ b/frontend/src/components/input-output/add-source/AddSource.css @@ -0,0 +1 @@ +/* Styles for AddSource */ \ No newline at end of file diff --git a/frontend/src/components/input-output/add-source/AddSource.jsx b/frontend/src/components/input-output/add-source/AddSource.jsx new file mode 100644 index 000000000..2a7d0e9e5 --- /dev/null +++ b/frontend/src/components/input-output/add-source/AddSource.jsx @@ -0,0 +1,117 @@ +import { Typography } from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import { handleException, sourceTypes } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useSessionStore } from "../../../store/session-store"; +import { EmptyState } from "../../widgets/empty-state/EmptyState"; +import { ConfigureDs } from "../configure-ds/ConfigureDs"; + +function AddSource({ + selectedSourceId, + setOpen, + type, + addNewItem, + editItemId, + metadata, + handleUpdate, +}) { + const [spec, setSpec] = useState({}); + const [formData, setFormData] = useState({}); + const [isLoading, setIsLoading] = useState(false); + const [oAuthProvider, setOAuthProvider] = useState(""); + const { sessionDetails } = useSessionStore(); + const { setAlertDetails } = useAlertStore(); + const axiosPrivate = useAxiosPrivate(); + + useEffect(() => { + if (!selectedSourceId) { + setSpec({}); + setOAuthProvider(""); + return; + } + + let url = `/api/v1/unstract/${sessionDetails?.orgId}`; + if (sourceTypes.connectors.includes(type)) { + url += `/connector_schema/?id=${selectedSourceId}`; + } else { + url += `/adapter_schema/?id=${selectedSourceId}`; + } + + const requestOptions = { + method: "GET", + url, + }; + + setIsLoading(true); + axiosPrivate(requestOptions) + .then((res) => { + const data = res?.data; + setSpec(data?.json_schema || {}); + if (data?.oauth) { + setOAuthProvider(data?.python_social_auth_backend); + } else { + setOAuthProvider(""); + } + }) + .catch((err) => { + setAlertDetails(handleException(err)); + }) + .finally(() => { + setIsLoading(false); + }); + }, [selectedSourceId]); + + useEffect(() => { + if (editItemId?.length && metadata && Object.keys(metadata)?.length) { + setFormData(metadata); + } + }, [metadata]); + + if (selectedSourceId.includes("pcs|")) { + return ( + + Edit is not supported for this connector + + ); + } + + if (!spec || !Object.keys(spec)?.length) { + return ; + } + + return ( + + ); +} + +AddSource.propTypes = { + selectedSourceId: PropTypes.string.isRequired, + setOpen: PropTypes.func, + type: PropTypes.string.isRequired, + addNewItem: PropTypes.func, + editItemId: PropTypes.string, + metadata: PropTypes.object, + handleUpdate: PropTypes.func, +}; + +export { AddSource }; diff --git a/frontend/src/components/input-output/configure-ds/ConfigureDs.css b/frontend/src/components/input-output/configure-ds/ConfigureDs.css new file mode 100644 index 000000000..8af01af91 --- /dev/null +++ b/frontend/src/components/input-output/configure-ds/ConfigureDs.css @@ -0,0 +1,23 @@ +/* Styles for ConfigureDs */ + +.config-layout { + width: 100%; + padding-bottom: 15px; +} + +.config-row { + margin-top: 10px; +} + +.config-col1 { + padding-right: 5px; +} + +.config-col2 { + padding-right: 5px; +} + +.config-tc-btn { + background-color: #4BB543 !important; +} + diff --git a/frontend/src/components/input-output/configure-ds/ConfigureDs.jsx b/frontend/src/components/input-output/configure-ds/ConfigureDs.jsx new file mode 100644 index 000000000..60c2f8cd6 --- /dev/null +++ b/frontend/src/components/input-output/configure-ds/ConfigureDs.jsx @@ -0,0 +1,284 @@ +import { Col, Row } from "antd"; +import PropTypes from "prop-types"; +import { createRef, useEffect, useState } from "react"; +import { useParams } from "react-router-dom"; + +import { + handleException, + sourceTypes, +} from "../../../helpers/GetStaticData.js"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { RjsfFormLayout } from "../../../layouts/rjsf-form-layout/RjsfFormLayout.jsx"; +import { useAlertStore } from "../../../store/alert-store"; +import { useSessionStore } from "../../../store/session-store"; +import { OAuthDs } from "../../oauth-ds/oauth-ds/OAuthDs.jsx"; +import { CustomButton } from "../../widgets/custom-button/CustomButton.jsx"; +import "./ConfigureDs.css"; + +function ConfigureDs({ + spec, + formData, + setFormData, + setOpen, + oAuthProvider, + selectedSourceId, + isLoading, + addNewItem, + type, + editItemId, + sourceType, + handleUpdate, +}) { + const formRef = createRef(null); + const axiosPrivate = useAxiosPrivate(); + const [isTcSuccessful, setIsTcSuccessful] = useState(false); + const [isTcLoading, setIsTcLoading] = useState(false); + const [isSubmitApiLoading, setIsSubmitApiLoading] = useState(false); + const [cacheKey, setCacheKey] = useState(""); + const [status, setStatus] = useState(""); + const { sessionDetails } = useSessionStore(); + const { setAlertDetails } = useAlertStore(); + + const { id } = useParams(); + + useEffect(() => { + if (isTcSuccessful) { + setIsTcSuccessful(false); + } + }, [formData]); + + const isFormValid = () => { + if (formRef) { + formRef?.current?.validateFields((errors, values) => { + if (errors) { + return false; + } + }); + } + return true; + }; + + const handleTestConnection = (updatedFormData) => { + // Check if there any error in form proceed to test connection only there is no error. + if (!isFormValid()) { + return; + } + if (oAuthProvider?.length && (status !== "success" || !cacheKey?.length)) { + setAlertDetails({ + type: "error", + content: "Invalid OAuth", + }); + return; + } + + let body = {}; + let url = `/api/v1/unstract/${sessionDetails?.orgId}/`; + + if (sourceType === Object.keys(sourceTypes)[0]) { + const connectorMetadata = { ...updatedFormData }; + delete connectorMetadata.connectorName; + body = { + connector_id: selectedSourceId, + connector_metadata: connectorMetadata, + }; + url += "test_connectors/"; + } else { + const adapterMetadata = { ...updatedFormData }; + delete adapterMetadata.adapterName; + body = { + adapter_id: selectedSourceId, + adapter_metadata: adapterMetadata, + adapter_type: type.toUpperCase(), + }; + url += "test_adapters/"; + } + + if (oAuthProvider?.length > 0) { + body["connector_metadata"] = { + ...body["connector_metadata"], + ...{ "oauth-key": cacheKey }, + }; + } + + const requestOptions = { + method: "POST", + url, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + "Content-Type": "application/json", + }, + data: body, + }; + + setIsTcLoading(true); + axiosPrivate(requestOptions) + .then((res) => { + const isValid = res?.data?.is_valid; + setIsTcSuccessful(isValid); + if (!isValid) { + setAlertDetails({ + type: "error", + content: "Test connection failed", + }); + } else { + setAlertDetails({ + type: "success", + content: "Test connection successful", + }); + } + }) + .catch((err) => { + setAlertDetails(handleException(err, "Test connection failed")); + }) + .finally(() => { + setIsTcLoading(false); + }); + }; + + const handleSubmit = () => { + if (!isTcSuccessful) { + setAlertDetails({ + type: "error", + content: "Please test the connection before submitting.", + }); + return; + } + + let body = {}; + let url = `/api/v1/unstract/${sessionDetails?.orgId}/`; + + if (sourceType === Object.keys(sourceTypes)[0]) { + const connectorMetadata = { ...formData }; + const connectorName = connectorMetadata?.connectorName; + delete connectorMetadata.connectorName; + body = { + workflow: id, + created_by: sessionDetails?.id, + connector_id: selectedSourceId, + connector_metadata: connectorMetadata, + connector_type: type.toUpperCase(), + connector_name: connectorName, + }; + url += "connector/"; + } else { + const adapterMetadata = { ...formData }; + const adapterName = adapterMetadata?.adapter_name; + delete adapterMetadata.adapter_name; + body = { + adapter_id: selectedSourceId, + adapter_metadata: adapterMetadata, + adapter_type: type.toUpperCase(), + adapter_name: adapterName, + }; + url += "adapter/"; + } + + let method = "POST"; + if (editItemId?.length) { + method = "PUT"; + url += `${editItemId}/`; + } + + if (oAuthProvider?.length > 0) { + const encodedCacheKey = encodeURIComponent(cacheKey); + url = url + `?oauth-key=${encodedCacheKey}`; + } + + const requestOptions = { + method, + url, + headers: { + "Content-Type": "application/json", + "X-CSRFToken": sessionDetails?.csrfToken, + }, + data: body, + }; + + setIsSubmitApiLoading(true); + axiosPrivate(requestOptions) + .then((res) => { + const data = res?.data; + if (sourceTypes.connectors.includes(type)) { + handleUpdate({ connector_instance: data?.id }); + setAlertDetails({ + type: "success", + content: "Successfully added connector", + }); + return; + } + if (data) { + addNewItem(data, !!editItemId); + } + setOpen(false); + }) + .catch((err) => { + setAlertDetails(handleException(err)); + }) + .finally(() => { + setIsSubmitApiLoading(false); + }); + }; + + return ( +
+ {!isLoading && oAuthProvider?.length > 0 && ( + + )} + + +
+ + Test Connection + + + + + Submit + + + + + + ); +} + +ConfigureDs.propTypes = { + spec: PropTypes.object, + formData: PropTypes.object.isRequired, + setFormData: PropTypes.func.isRequired, + setOpen: PropTypes.func, + oAuthProvider: PropTypes.string, + selectedSourceId: PropTypes.string, + isLoading: PropTypes.bool.isRequired, + addNewItem: PropTypes.func, + type: PropTypes.string, + editItemId: PropTypes.string, + sourceType: PropTypes.string.isRequired, + handleUpdate: PropTypes.func, +}; + +export { ConfigureDs }; diff --git a/frontend/src/components/input-output/data-source-card/DataSourceCard.css b/frontend/src/components/input-output/data-source-card/DataSourceCard.css new file mode 100644 index 000000000..0eaba639c --- /dev/null +++ b/frontend/src/components/input-output/data-source-card/DataSourceCard.css @@ -0,0 +1,27 @@ +.ds-card { + background-color: white; + border: 1px solid #0000000F; + width: 240px; +} + +.ds-card .ant-card-body { + padding: 0px; +} + + .ds-card .cover-img { + height: 180px; + width: 90%; + text-align: center; + padding: 10px; + background-color: transparent; + display: flex; + align-items: center; + overflow: hidden; + } + +.ds-card-name { + width: 100%; + border-top: 1px solid #0000000F; + padding: 10px 0px; + background-color: #00000005; +} diff --git a/frontend/src/components/input-output/data-source-card/DataSourceCard.jsx b/frontend/src/components/input-output/data-source-card/DataSourceCard.jsx new file mode 100644 index 000000000..a3fcd05c0 --- /dev/null +++ b/frontend/src/components/input-output/data-source-card/DataSourceCard.jsx @@ -0,0 +1,38 @@ +import { Card, Image, Typography } from "antd"; +import PropTypes from "prop-types"; + +import "./DataSourceCard.css"; + +function DataSourceCard({ srcDetails, setSelectedSourceId }) { + return ( + + + + } + onClick={() => setSelectedSourceId(srcDetails?.id)} + > +
+ {srcDetails?.name} +
+
+ ); +} + +DataSourceCard.propTypes = { + srcDetails: PropTypes.object.isRequired, + setSelectedSourceId: PropTypes.func.isRequired, +}; + +export { DataSourceCard }; diff --git a/frontend/src/components/input-output/edit-ds-modal/EditDsModal.css b/frontend/src/components/input-output/edit-ds-modal/EditDsModal.css new file mode 100644 index 000000000..220d9afaa --- /dev/null +++ b/frontend/src/components/input-output/edit-ds-modal/EditDsModal.css @@ -0,0 +1,11 @@ +/* Styles for EditDsModal */ + +.edit-ds-layout { + max-height: 800px; + overflow-y: scroll; + margin-top: 10px; +} + +.edit-ds-modal { + width: 25% !important; +} \ No newline at end of file diff --git a/frontend/src/components/input-output/edit-ds-modal/EditDsModal.jsx b/frontend/src/components/input-output/edit-ds-modal/EditDsModal.jsx new file mode 100644 index 000000000..0d31c6ee6 --- /dev/null +++ b/frontend/src/components/input-output/edit-ds-modal/EditDsModal.jsx @@ -0,0 +1,117 @@ +import { Modal } from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; +import axios from "axios"; + +import "./EditDsModal.css"; +import { ConfigureDs } from "../configure-ds/ConfigureDs.jsx"; +import { useSessionStore } from "../../../store/session-store"; +import { CONNECTOR_TYPE_MAP } from "../../../helpers/GetStaticData"; +import { useAlertStore } from "../../../store/alert-store"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate.js"; + +function EditDsModal({ + isOpen, + setOpen, + currentConnectorId, + connectorType, + setReloadList, +}) { + const [dsSelected, setDsSelected] = useState(""); + const [spec, setSpec] = useState({}); + const [isSpecLoading, setIsSpecLoading] = useState(false); + const [oAuthProvider, setOAuthProvider] = useState(""); + const { sessionDetails } = useSessionStore(); + const { setAlertDetails } = useAlertStore(); + const axiosPrivate = useAxiosPrivate(); + const [connectorData, setConnectorData] = useState({}); + + const orgId = sessionDetails?.orgId; + + useEffect(() => { + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${orgId}/connector/${currentConnectorId}/`, + }; + + axiosPrivate(requestOptions) + .then((res) => { + setDsSelected(res?.data?.connector_id); + setConnectorData(res?.data); + }) + .catch((err) => { + setAlertDetails({ + type: "error", + content: "Failed to fetch the connector data.", + }); + }); + }, [currentConnectorId]); + + useEffect(() => { + if (dsSelected.length === 0) return; + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${orgId}/connector_schema/?id=${dsSelected}`, + }; + + setIsSpecLoading(true); + axios(requestOptions) + .then((res) => { + const data = res?.data; + setSpec(data?.json_schema); + if (data?.oauth) { + setOAuthProvider(data?.python_social_auth_backend); + } + }) + .catch((err) => { + setAlertDetails({ + type: "error", + content: "Failed to fetch the data source details.", + }); + }) + .finally(() => { + setIsSpecLoading(false); + }); + }, [dsSelected]); + + const handleCancel = () => { + setReloadList(true); + setOpen(false); + }; + + return ( + +
+ {connectorData && ( + + )} +
+
+ ); +} + +EditDsModal.propTypes = { + isOpen: PropTypes.bool.isRequired, + setOpen: PropTypes.func.isRequired, + currentConnectorId: PropTypes.string, + connectorType: PropTypes.string, + setReloadList: PropTypes.func.isRequired, +}; + +export { EditDsModal }; diff --git a/frontend/src/components/input-output/file-system/FileSystem.css b/frontend/src/components/input-output/file-system/FileSystem.css new file mode 100644 index 000000000..40872f4f0 --- /dev/null +++ b/frontend/src/components/input-output/file-system/FileSystem.css @@ -0,0 +1,52 @@ +.storageExplorer { + height: 100%; + overflow: hidden; +} + +.explorerTree { + height: calc(100% - 66px); + overflow: auto; + padding-inline: 8px; + padding-block: 8px; + margin-block-start: 4px; +} + +.fileHeading { + padding-inline-start: 16px; + margin-block-start: 8px; +} + +.fileText { + width: calc(100% - 26px); + display: inline-grid; + grid-template-columns: 1fr auto auto; + column-gap: 20px; + margin-inline-start: 2px; +} + +.toolBar { + display: grid; + grid-template-columns: 1fr auto auto auto auto auto; + align-items: center; + column-gap: 12px; +} + +.ant-dropdown-menu-title-content > .settings-button { + color: inherit; + border-color: transparent; + background: inherit; + box-shadow: none; + text-align: left; + padding: 0; + height: auto; + border-radius: 0; +} + +.ant-dropdown-menu-title-content > .settings-button:active { + color: inherit; + border-color: transparent; +} + +.ant-tree-treenode-selected .ant-typography{ + color: #fff !important; +} \ No newline at end of file diff --git a/frontend/src/components/input-output/file-system/FileSystem.jsx b/frontend/src/components/input-output/file-system/FileSystem.jsx new file mode 100644 index 000000000..c70a5769a --- /dev/null +++ b/frontend/src/components/input-output/file-system/FileSystem.jsx @@ -0,0 +1,195 @@ +import { CaretDownOutlined } from "@ant-design/icons"; +import { Tree, Typography } from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useRef, useState } from "react"; + +import { Document, Folder } from "../../../assets"; +import { formatBytes } from "../../../helpers/GetStaticData"; +import { inputService } from "../../input-output/input-output/input-service.js"; +import { SpinnerLoader } from "../../widgets/spinner-loader/SpinnerLoader.jsx"; + +import "./FileSystem.css"; + +const { DirectoryTree } = Tree; +const { Text } = Typography; + +function FileExplorer({ selectedItem = "", data = [], loadingData, error }) { + const inpService = inputService(); + + const [tree, setTree] = useState([]); + const [expandedKeys, setExpandedKeys] = useState([]); + const [selectedKeys, setSelectedKeys] = useState([]); + const [autoExpandParent, setAutoExpandParent] = useState(true); + + const uploadPathRef = useRef(""); + + useEffect(() => { + const treeData = structuredClone(data); + updateTree(treeData); + }, [data, loadingData, error]); + + useEffect(() => { + // Clear selected items/keys when the data source is changed. + setExpandedKeys([]); + setSelectedKeys([]); + }, [selectedItem]); + + function onLoadData({ key, children }) { + return new Promise((resolve) => { + if (children) { + resolve(); + return; + } + getAndUpdateFiles(key) + .then(() => { + resolve(); + }) + .catch(() => {}); + }); + } + + function getAndUpdateFiles(path) { + return inpService + .getFileList(selectedItem, path) + .then((res) => { + let newTree = tree; + if (path) { + const targetNode = getTargetNode(path, newTree); + targetNode["children"] = res.data; + } else { + newTree = res.data; + } + updateTree(newTree); + }) + .catch(() => { + console.error( + `Unable to get files on "${selectedItem}" for the folder "${path}"` + ); + }); + } + + function onSelect(selectedKeys, event) { + setSelectedKeys(selectedKeys); + if (event.node.isLeaf) { + uploadPathRef.current = ""; + } else { + uploadPathRef.current = event.node.key; + } + } + + function onExpand(newExpandedKeys) { + setExpandedKeys(newExpandedKeys); + setAutoExpandParent(false); + } + + function updateTree(treeData) { + transformTree(treeData); + setTree([...treeData]); + setSelectedKeys([]); + } + + return ( +
+ {tree.length !== 0 && ( + <> +
+ + Name + + + Size + + + Modified at + +
+ } + expandedKeys={expandedKeys} + selectedKeys={selectedKeys} + autoExpandParent={autoExpandParent} + onExpand={onExpand} + onSelect={onSelect} + loadData={onLoadData} + expandAction={false} + /> + + )} + {loadingData && } + {tree?.length === 0 && !error && ( +
+ No files +
+ )} + {error && ( +
+ Error loading the data +
+ )} +
+ ); +} + +FileExplorer.propTypes = { + data: PropTypes.array, +}; + +function getTargetNode(key, treeData) { + let targetNode; + for (const node of treeData) { + if (node.key === key) { + targetNode = node; + break; + } else if (node.children) { + const findTargetNode = getTargetNode(key, node.children); + if (findTargetNode) { + targetNode = findTargetNode; + break; + } + } + } + return targetNode; +} + +function transformTree(tree) { + let key = ""; + let title = ""; + let isFile = ""; + let modifiedDate = ""; + let size = ""; + + tree.forEach((node) => { + key = node.name; + title = key.split("/").at(-1); + isFile = node.type === "file"; + modifiedDate = node.modified_at?.split(" ")[0] || ""; + size = isFile ? formatBytes(node.size) : ""; + + node["key"] = key; + node["icon"] = isFile ? : ; + node["title"] = ( +
+ {title} + {size} + {modifiedDate} +
+ ); + node["isLeaf"] = isFile; + + if (node.children) { + transformTree(node.children); + } + }); +} + +FileExplorer.propTypes = { + selectedItem: PropTypes.string, + data: PropTypes.array, + loadingData: PropTypes.bool, + error: PropTypes.bool, +}; + +export { FileExplorer }; diff --git a/frontend/src/components/input-output/input-output/InputOutput.css b/frontend/src/components/input-output/input-output/InputOutput.css new file mode 100644 index 000000000..b66d489d3 --- /dev/null +++ b/frontend/src/components/input-output/input-output/InputOutput.css @@ -0,0 +1,14 @@ +.input-layout { + height: 100%; +} + +.input-sidebar { + background-color: var(--page-bg-3); + padding: 12px; +} + +.input-main { + padding: 12px; + height: 100%; + background-color: var(--white); +} diff --git a/frontend/src/components/input-output/input-output/InputOutput.jsx b/frontend/src/components/input-output/input-output/InputOutput.jsx new file mode 100644 index 000000000..2d899fdd0 --- /dev/null +++ b/frontend/src/components/input-output/input-output/InputOutput.jsx @@ -0,0 +1,171 @@ +import { Col, Image, Row } from "antd"; +import { useEffect, useState } from "react"; +import { useLocation, useParams } from "react-router-dom"; + +import { + CONNECTOR_TYPE_MAP, + handleException, +} from "../../../helpers/GetStaticData.js"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useSessionStore } from "../../../store/session-store"; +import { AddSourceModal } from "../add-source-modal/AddSourceModal.jsx"; +import { ManageFiles } from "../manage-files/ManageFiles.jsx"; +import { Sidebar } from "../sidebar/Sidebar.jsx"; +import "./InputOutput.css"; +const INPUT = "input"; +const OUTPUT = "output"; + +function InputOutput() { + const [selectedItem, setSelectedItem] = useState(); + const [listOfItems, setListOfItems] = useState([]); + const [openModal, setOpenModal] = useState(false); + const [connectorType, setConnectorType] = useState(""); + const [reloadList, setReloadList] = useState(false); + const [editItemId, setEditItemId] = useState(null); + const { sessionDetails } = useSessionStore(); + const { setAlertDetails } = useAlertStore(); + const { id } = useParams(); + const axiosPrivate = useAxiosPrivate(); + const location = useLocation(); + const currentPath = location.pathname; + + const sourceIcon = (src) => { + return ; + }; + + useEffect(() => { + const currentPathSplit = currentPath.split("/"); + const currentPathLastIndex = currentPathSplit?.length - 1; + + const type = currentPathSplit[currentPathLastIndex]; + + if (type !== INPUT && type !== OUTPUT) { + return; + } + + setConnectorType(type); + + const requestOptions = { + method: "GET", + url: `/api/v1/unstract/${ + sessionDetails?.orgId + }/connector/?workflow=${id}&connector_type=${type.toUpperCase()}`, + }; + + axiosPrivate(requestOptions) + .then((res) => { + const sources = res?.data; + if (sources?.length === 0) { + setSelectedItem(""); + setListOfItems([]); + return; + } + const menuItems = sources.map((item) => + getItem(item?.connector_name, item?.id, sourceIcon(item?.icon)) + ); + const firstId = sources[0].id.toString(); + setSelectedItem(firstId); + setListOfItems(menuItems); + }) + .catch((err) => { + setAlertDetails(handleException(err)); + }) + .finally(() => { + setReloadList(false); + }); + }, [currentPath, reloadList]); + + const getItem = (label, key, icon, children, type) => { + return { + key, + icon, + children, + label, + type, + }; + }; + + const handleOpenModal = () => { + setOpenModal(true); + }; + + const handleDelete = () => { + const requestOptions = { + method: "DELETE", + url: `/api/v1/unstract/${sessionDetails?.orgId}/connector/${selectedItem}/`, + headers: { + "X-CSRFToken": sessionDetails?.csrfToken, + }, + }; + + axiosPrivate(requestOptions) + .then(() => { + setReloadList(true); + }) + .catch((err) => { + setAlertDetails(handleException(err)); + }); + }; + + const addNewItem = (newItem, isEdit) => { + let items = [...listOfItems]; + if (isEdit) { + items = [...listOfItems].map((item) => { + if (item?.key !== newItem?.id) { + return item; + } + item["label"] = newItem?.connector_name; + return item; + }); + } else { + const itemToAdd = getItem( + newItem?.connector_name, + newItem?.id, + sourceIcon(newItem?.icon) + ); + items.push(itemToAdd); + } + setListOfItems(items); + + setSelectedItem(newItem?.id); + }; + + return ( + <> + {connectorType?.length > 0 && ( + <> + +
+ + + + + + + + + )} + + ); +} + +export { InputOutput }; diff --git a/frontend/src/components/input-output/input-output/input-service.js b/frontend/src/components/input-output/input-output/input-service.js new file mode 100644 index 000000000..8a0da3350 --- /dev/null +++ b/frontend/src/components/input-output/input-output/input-service.js @@ -0,0 +1,26 @@ +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate.js"; +import { useSessionStore } from "../../../store/session-store.js"; + +let options = {}; + +function inputService() { + const axiosPrivate = useAxiosPrivate(); + const { sessionDetails } = useSessionStore(); + const path = `/api/v1/unstract/${sessionDetails.orgId.replaceAll('"', "")}`; + + return { + getFileList: (storageId, filePath = "/") => { + options = { + url: `${path}/file`, + method: "GET", + params: { + connector_id: storageId, + path: filePath, + }, + }; + return axiosPrivate(options); + }, + }; +} + +export { inputService }; diff --git a/frontend/src/components/input-output/list-of-sources/ListOfSources.css b/frontend/src/components/input-output/list-of-sources/ListOfSources.css new file mode 100644 index 000000000..45a6aae11 --- /dev/null +++ b/frontend/src/components/input-output/list-of-sources/ListOfSources.css @@ -0,0 +1,15 @@ +/* Styles for ListOfAdapters */ + +.list-of-srcs { + height: 600px; + overflow-y: auto; + overflow-x: hidden; +} + +.list-of-srcs > .searchbox { + max-width: 300px; +} + +.list-of-srcs > .list { + padding-top: 20px; +} \ No newline at end of file diff --git a/frontend/src/components/input-output/list-of-sources/ListOfSources.jsx b/frontend/src/components/input-output/list-of-sources/ListOfSources.jsx new file mode 100644 index 000000000..f2413fcca --- /dev/null +++ b/frontend/src/components/input-output/list-of-sources/ListOfSources.jsx @@ -0,0 +1,114 @@ +import { SearchOutlined } from "@ant-design/icons"; +import { Input, List } from "antd"; +import debounce from "lodash/debounce"; +import PropTypes from "prop-types"; +import { useCallback, useEffect, useState } from "react"; + +import { handleException, sourceTypes } from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate"; +import { useAlertStore } from "../../../store/alert-store"; +import { useSessionStore } from "../../../store/session-store"; +import { SpinnerLoader } from "../../widgets/spinner-loader/SpinnerLoader"; +import { DataSourceCard } from "../data-source-card/DataSourceCard"; +import "./ListOfSources.css"; + +function ListOfSources({ setSelectedSourceId, type }) { + const [sourcesList, setSourcesList] = useState([]); + const [filteredSourcesList, setFilteredSourcesList] = useState([]); + const [searchText, setSearchText] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const { sessionDetails } = useSessionStore(); + const { setAlertDetails } = useAlertStore(); + const axiosPrivate = useAxiosPrivate(); + + useEffect(() => { + if (searchText?.length === 0) { + setFilteredSourcesList(sourcesList); + } + const filteredList = [...sourcesList].filter((source) => { + const name = source?.name?.toUpperCase(); + const searchUpperCase = searchText.toUpperCase(); + return name.includes(searchUpperCase); + }); + setFilteredSourcesList(filteredList); + }, [sourcesList, searchText]); + + useEffect(() => { + if (!type) { + setSourcesList([]); + return; + } + getListOfSources(); + }, [type, open]); + + const getListOfSources = () => { + let url = `/api/v1/unstract/${sessionDetails?.orgId}`; + if (sourceTypes.connectors.includes(type)) { + url += `/supported_connectors/?type=${type.toUpperCase()}`; + } else { + url += `/supported_adapters/?adapter_type=${type.toUpperCase()}`; + } + // API to get the list of adapters. + const requestOptions = { + method: "GET", + url, + }; + + setIsLoading(true); + setSourcesList([]); + axiosPrivate(requestOptions) + .then((res) => { + setSourcesList(res?.data || []); + }) + .catch((err) => { + setAlertDetails(handleException(err)); + }) + .finally(() => { + setIsLoading(false); + }); + }; + + const onSearchDebounce = useCallback( + debounce(({ target: { value } }) => { + setSearchText(value); + }, 600), + [] + ); + + if (isLoading) { + return ; + } + + return ( +
+
+ } + onChange={onSearchDebounce} + /> +
+
+ ( + + + + )} + /> +
+
+ ); +} + +ListOfSources.propTypes = { + setSelectedSourceId: PropTypes.func.isRequired, + type: PropTypes.string.isRequired, +}; + +export { ListOfSources }; diff --git a/frontend/src/components/input-output/manage-files/ManageFiles.css b/frontend/src/components/input-output/manage-files/ManageFiles.css new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/components/input-output/manage-files/ManageFiles.jsx b/frontend/src/components/input-output/manage-files/ManageFiles.jsx new file mode 100644 index 000000000..75b2aa041 --- /dev/null +++ b/frontend/src/components/input-output/manage-files/ManageFiles.jsx @@ -0,0 +1,46 @@ +import { useState, useEffect } from "react"; +import PropTypes from "prop-types"; + +import { inputService } from "../../input-output/input-output/input-service.js"; +import { FileExplorer } from "../file-system/FileSystem.jsx"; + +function ManageFiles({ selectedItem }) { + const inpService = inputService(); + + const [files, setFiles] = useState([]); + const [loadingData, setLoadingData] = useState(false); + const [error, setError] = useState(false); + + useEffect(() => { + setFiles([]); + if (!selectedItem) return; + setLoadingData(true); + inpService + .getFileList(selectedItem) + .then((res) => { + setFiles(res.data); + setError(false); + }) + .catch(() => { + setError(true); + }) + .finally(() => { + setLoadingData(false); + }); + }, [selectedItem]); + + return ( + + ); +} + +ManageFiles.propTypes = { + selectedItem: PropTypes.string, +}; + +export { ManageFiles }; diff --git a/frontend/src/components/input-output/sidebar/Sidebar.css b/frontend/src/components/input-output/sidebar/Sidebar.css new file mode 100644 index 000000000..9663abe5c --- /dev/null +++ b/frontend/src/components/input-output/sidebar/Sidebar.css @@ -0,0 +1,16 @@ +.sidebar-layout { + margin: 5px; +} + +.sidebar-menu { + margin-top: 10px; + background-color: transparent; +} + +.sidebar-menu .ant-menu-item { + padding: 5px !important; +} + +.sidebar-menu .ant-menu-title-content { + margin-left: 5px; +} diff --git a/frontend/src/components/input-output/sidebar/Sidebar.jsx b/frontend/src/components/input-output/sidebar/Sidebar.jsx new file mode 100644 index 000000000..d59968cdb --- /dev/null +++ b/frontend/src/components/input-output/sidebar/Sidebar.jsx @@ -0,0 +1,46 @@ +import { Button, Menu } from "antd"; +import { PlusOutlined } from "@ant-design/icons"; +import PropTypes from "prop-types"; + +import "./Sidebar.css"; + +function Sidebar({ + selectedItem, + setSelectedItem, + listOfItems, + handleOpenModal, + btnText, +}) { + const handleSelectItem = (e) => { + const id = e.key; + setSelectedItem(id?.toString()); + }; + + return ( +
+ + {selectedItem && ( + + )} +
+ ); +} + +Sidebar.propTypes = { + selectedItem: PropTypes.string, + setSelectedItem: PropTypes.func, + listOfItems: PropTypes.array, + handleOpenModal: PropTypes.func.isRequired, + btnText: PropTypes.string.isRequired, +}; + +export { Sidebar }; diff --git a/frontend/src/components/log-in/Login.css b/frontend/src/components/log-in/Login.css new file mode 100644 index 000000000..78fae446b --- /dev/null +++ b/frontend/src/components/log-in/Login.css @@ -0,0 +1,80 @@ +.login-main { + width: 100%; + height: 100vh; + display: flex; +} + +.login-left-section { + width: 50%; + display: flex; + justify-content: center; + align-items: center; + background-color: #fff; +} + +.login-right-section { + width: 50%; + background-color: #ECEFF3; +} +.right-section-text-wrapper{ + display: flex; + justify-content: center; + height: 50%; + flex-direction: column; +} +.right-title-cover{ + width: 75%; + margin: 0 auto; +} +.right-subtitle-cover{ + width: 60%; + margin: 0 auto; +} +.right-subtitle{ + color:#3D6182; + font-size: 20px; +} +.login-background{ + width: 20%; + position: absolute; + bottom: 12%; + right: 14%; + border-radius: 5px; +} + +.button-wraper { + width: 450px; + height: 550px; + position: fixed; + display: flex; + flex-direction: column; + gap: 10px; + justify-content: center; +} + +.logo { + height: 50px; +} + +.text-wrapper { + height: 50%; + width: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.login-button { + width: 80%; + margin: 0 auto; + height: 50px; + background-color: #2F93F6; + color: #fff; + font-size: 18px; +} + +.signin-text-wrapper{ + display: flex; + justify-content: center; +} \ No newline at end of file diff --git a/frontend/src/components/log-in/Login.jsx b/frontend/src/components/log-in/Login.jsx new file mode 100644 index 000000000..bcd1a7be7 --- /dev/null +++ b/frontend/src/components/log-in/Login.jsx @@ -0,0 +1,61 @@ +import { Button, Typography } from "antd"; + +import logo from "../../assets/UnstractLogoBlack.svg"; +import loginBG from "../../assets/login-page-bg.svg"; +import { getBaseUrl } from "../../helpers/GetStaticData"; +import "./Login.css"; + +function Login() { + const baseUrl = getBaseUrl(); + const newURL = baseUrl + "/api/v1/login"; + const handleLogin = () => { + window.location.href = newURL; + }; + + return ( +
+
+
+ Logo +
+ Sign Up + + Try Unstract free for 14 days. No credit card required. + +
+ +
+ + Already have an account? Sign in + +
+
+
+
+
+
+ + UNLOCK VALUE FROM UNSTRUCTURED DATA. + +
+
+ + Unstract is a no-code LLM platform that lets you automate even the + most complex workflows involving unstructured data, saving you + time, money, and automation headaches. + +
+
+ login background +
+
+ ); +} + +export { Login }; diff --git a/frontend/src/components/navigations/side-nav-bar/SideNavBar.css b/frontend/src/components/navigations/side-nav-bar/SideNavBar.css new file mode 100644 index 000000000..eed76f741 --- /dev/null +++ b/frontend/src/components/navigations/side-nav-bar/SideNavBar.css @@ -0,0 +1,106 @@ +.side-bar { + background-color: #0d3a63 !important; + overflow-y: auto; +} + +.secondary-list-wrapper { + padding: 10px 0px; +} + +.secondary-list-wrapper .sidebar-item-icons { + margin-top: 1; + height: auto; + width: 25px; +} + +.side-bar .menu-item-body { + padding: 10px 0px; + width: 100%; +} + +.side-bar .menu-item-icon { + margin-top: 1; + height: auto; + width: 25px; +} + +.space-styles-active .menu-item-icon, +.space-styles:hover .menu-item-icon { + filter: brightness(0) invert(1); +} + +.sidebar-footer-icons { + color: white; + font-size: 20px; +} +.sidebar-footer-text { + color: white; + padding-left: 10px; +} + +.space-styles { + cursor: pointer; + padding: 10px 8px; + border-radius: 8px; + width: 100%; +} + +.space-styles-active, +.space-styles:hover { + background: #005b82; +} + +.space-styles-disable { + cursor: not-allowed; +} + +.sidebar-main-heading { + color: white; + font-weight: 600; + font-size: 15px; +} + +.sidebar-item-text { + color: #b4c2cf; + text-align: left; +} + +.space-styles-active .sidebar-item-text { + color: white; +} + +.space-styles:hover .sidebar-item-text { + color: white; +} + +.slider-wrap { + padding: 12px; +} + +.collapse-footer { + width: 65px; +} + +.full-footer { + width: 240px; +} + +.fs-14 { + font-size: 14px; +} + +.fs-11 { + font-size: 11px; + opacity: 0.8; +} + +.main-slider { + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.sidebar-divider { + background-color: rgba(255, 255, 255, 0.3); + margin: 10px 0; +} diff --git a/frontend/src/components/navigations/side-nav-bar/SideNavBar.jsx b/frontend/src/components/navigations/side-nav-bar/SideNavBar.jsx new file mode 100644 index 000000000..d8ccdca6a --- /dev/null +++ b/frontend/src/components/navigations/side-nav-bar/SideNavBar.jsx @@ -0,0 +1,217 @@ +import { BranchesOutlined } from "@ant-design/icons"; +import { Divider, Image, Layout, Space, Tooltip, Typography } from "antd"; +import PropTypes from "prop-types"; +import { useNavigate } from "react-router-dom"; +import "./SideNavBar.css"; +const { Sider } = Layout; + +import Workflows from "../../../assets/Workflows.svg"; +import apiDeploy from "../../../assets/api-deployments.svg"; +import appdev from "../../../assets/appdev.svg"; +import CustomTools from "../../../assets/custom-tools-icon.svg"; +import EmbeddingIcon from "../../../assets/embedding.svg"; +import etl from "../../../assets/etl.svg"; +import LlmIcon from "../../../assets/llm.svg"; +import PlatformSettingsIcon from "../../../assets/platform-settings.svg"; +import task from "../../../assets/task.svg"; +import VectorDbIcon from "../../../assets/vector-db.svg"; +import { useSessionStore } from "../../../store/session-store"; + +const SideNavBar = ({ collapsed }) => { + const navigate = useNavigate(); + const { sessionDetails } = useSessionStore(); + const { orgName } = sessionDetails; + + const data = [ + { + id: 1, + mainTitle: "MANAGE", + subMenu: [ + { + id: 1.1, + title: "API Deployments", + description: "Unstructured to structured APIs", + image: apiDeploy, + path: `/${orgName}/api`, + active: window.location.pathname.startsWith(`/${orgName}/api`), + }, + { + id: 1.2, + title: "App Deployments", + description: "Standalone unstructured data apps", + icon: BranchesOutlined, + image: appdev, + path: `/${orgName}/app`, + active: window.location.pathname.startsWith(`/${orgName}/app`), + }, + { + id: 1.3, + title: "ETL Pipelines", + description: "Unstructured to structured data pipelines", + image: etl, + path: `/${orgName}/etl`, + active: window.location.pathname.startsWith(`/${orgName}/etl`), + }, + { + id: 1.4, + title: "Task Pipelines", + description: "Ad-hoc unstructured data task pipelines", + image: task, + path: `/${orgName}/task`, + active: window.location.pathname.startsWith(`/${orgName}/task`), + }, + ], + }, + { + id: 2, + mainTitle: "BUILD", + subMenu: [ + { + id: 2.1, + title: "Workflows", + description: "Build no-code data workflows for unstructured data", + icon: BranchesOutlined, + image: Workflows, + path: `/${orgName}/workflows`, + active: window.location.pathname.startsWith(`/${orgName}/workflows`), + }, + { + id: 2.2, + title: "Prompt Studio", + description: "Create structured data from unstructured documents", + image: CustomTools, + path: `/${orgName}/tools`, + active: window.location.pathname.startsWith(`/${orgName}/tools`), + }, + ], + }, + { + id: 3, + mainTitle: "SETTINGS", + subMenu: [ + { + id: 3.1, + title: "LLMs", + description: "Setup platform wide access to Large Language Models", + icon: BranchesOutlined, + image: LlmIcon, + path: `/${orgName}/settings/llms`, + active: window.location.pathname.startsWith( + `/${orgName}/settings/llms` + ), + }, + { + id: 3.2, + title: "Vector DBs", + description: "Setup platform wide access to Vector DBs", + image: VectorDbIcon, + path: `/${orgName}/settings/vectorDbs`, + active: window.location.pathname.startsWith( + `/${orgName}/settings/vectorDbs` + ), + }, + { + id: 3.3, + title: "Embedding", + description: "Setup platform wide access to Embedding models", + image: EmbeddingIcon, + path: `/${orgName}/settings/embedding`, + active: window.location.pathname.startsWith( + `/${orgName}/settings/embedding` + ), + }, + { + id: 3.4, + title: "Text Extractor", + description: "Setup platform wide access to Text extractor services", + image: EmbeddingIcon, + path: `/${orgName}/settings/textExtractor`, + active: window.location.pathname.startsWith( + `/${orgName}/settings/textExtractor` + ), + }, + { + id: 3.5, + title: "Platform", + description: "Settings for the platform", + image: PlatformSettingsIcon, + path: `/${orgName}/settings`, + active: + window.location.pathname === `/${orgName}/settings` || + window.location.pathname === `/${orgName}/settings/platform` || + window.location.pathname === `/${orgName}/settings/triad` || + window.location.pathname === `/${orgName}/users`, + }, + ], + }, + ]; + + return ( + +
+
+ {data?.map((item, index) => { + return ( +
+ {!collapsed && ( + + {item.mainTitle} + + )} + + {item.subMenu.map((el) => { + return ( + + { + !el.disable && navigate(el.path); + }} + > + + {!collapsed && ( +
+ + {el.title} + + + {el.description} + +
+ )} +
+
+ ); + })} +
+ {index < data.length - 1 && ( + + )} +
+ ); + })} +
+
+
+ ); +}; + +SideNavBar.propTypes = { + collapsed: PropTypes.bool.isRequired, +}; + +export default SideNavBar; diff --git a/frontend/src/components/navigations/top-nav-bar/TopNavBar.css b/frontend/src/components/navigations/top-nav-bar/TopNavBar.css new file mode 100644 index 000000000..6a09d4035 --- /dev/null +++ b/frontend/src/components/navigations/top-nav-bar/TopNavBar.css @@ -0,0 +1,43 @@ +/* Styles for TopNavBar */ + +.top-navbar-dp { + height: 25px; + width: 25px; + display: flex; + align-items: center; + justify-content: center; + background-color: #184772; + border-radius: 5px; + cursor: pointer; +} + +.top-navbar-dp .navbar-img { + border-radius: 5px; +} + +.top-navbar-dp .initials { + font-size: 12px; + font-weight: bold; + color: white; +} + +.topbar-logo { + width: 120px; + height: auto; + margin-inline-end: 12px; +} +.logout-button{ + color: inherit; + background: inherit; + box-shadow: none; + text-align: left; + padding: 0; + height: auto; + border-radius: 0; + border-color: transparent; +} + +.logout-button:active{ + color: inherit !important; + border-color: transparent !important; +} \ No newline at end of file diff --git a/frontend/src/components/navigations/top-nav-bar/TopNavBar.jsx b/frontend/src/components/navigations/top-nav-bar/TopNavBar.jsx new file mode 100644 index 000000000..9bfec966a --- /dev/null +++ b/frontend/src/components/navigations/top-nav-bar/TopNavBar.jsx @@ -0,0 +1,148 @@ +import { + Alert, + Button, + Col, + Dropdown, + Image, + Row, + Switch, + Typography, +} from "antd"; +import { useEffect } from "react"; +import { useNavigate } from "react-router-dom"; + +import { MoonIcon, SunIcon, UnstractLogo } from "../../../assets/index.js"; +import { THEME, getBaseUrl } from "../../../helpers/GetStaticData.js"; +import useLogout from "../../../hooks/useLogout.js"; +import "../../../layouts/page-layout/PageLayout.css"; +import { useSessionStore } from "../../../store/session-store.js"; +import "./TopNavBar.css"; + +// const PREFERS_DARK_THEME = window.matchMedia("(prefers-color-scheme: dark)"); + +function TopNavBar() { + const navigate = useNavigate(); + const { sessionDetails } = useSessionStore(); + const { orgName, adapters } = sessionDetails; + const updateSessionDetails = useSessionStore( + (state) => state.updateSessionDetails + ); + const baseUrl = getBaseUrl(); + const onBoardUrl = baseUrl + `/${orgName}/onboard`; + const logout = useLogout(); + + // Dropdown items + const items = [ + { + key: "1", + label: ( + + ), + }, + { + key: "2", + label: ( + + ), + }, + ]; + + useEffect(() => { + // if (PREFERS_DARK_THEME.matches) { + // document.body.classList.add(THEME.DARK); + // updateTheme(THEME.DARK); + // } + updateTheme(THEME.LIGHT); + }, []); + + function updateTheme(theme = THEME.LIGHT) { + updateSessionDetails({ currentTheme: theme }); + } + + function changeTheme(checked) { + if (checked) { + document.body.classList.add(THEME.DARK); + } else { + document.body.classList.remove(THEME.DARK); + } + updateTheme(checked ? THEME.DARK : THEME.LIGHT); + } + // Function to get the initials from the user name + const getInitials = (name) => { + const names = name.split(" "); + const initials = names + .map((n) => n.charAt(0)) + .join("") + .toUpperCase(); + return initials; + }; + + return ( + +
+ + + + {adapters.length < 3 && ( + + Complete it to start using Unstract. + + } + /> + )} + + + + + } + unCheckedChildren={} + disabled + /> + + + +
+ {sessionDetails?.picture ? ( + + ) : ( + + {getInitials(sessionDetails?.name)} + + )} +
+
+ + + + + ); +} + +export { TopNavBar }; diff --git a/frontend/src/components/oauth-ds/google/GoogleOAuthButton.css b/frontend/src/components/oauth-ds/google/GoogleOAuthButton.css new file mode 100644 index 000000000..b54b2ead7 --- /dev/null +++ b/frontend/src/components/oauth-ds/google/GoogleOAuthButton.css @@ -0,0 +1,5 @@ +/* Styles for GoogleOAuthButton */ + +.google-oauth-layout { + margin-bottom: 20px; +} \ No newline at end of file diff --git a/frontend/src/components/oauth-ds/google/GoogleOAuthButton.jsx b/frontend/src/components/oauth-ds/google/GoogleOAuthButton.jsx new file mode 100644 index 000000000..a3ee1668f --- /dev/null +++ b/frontend/src/components/oauth-ds/google/GoogleOAuthButton.jsx @@ -0,0 +1,32 @@ +import PropTypes from "prop-types"; +import { GoogleLoginButton } from "react-social-login-buttons"; +import { useEffect, useState } from "react"; +import { Typography } from "antd"; + +import "./GoogleOAuthButton.css"; + +const GoogleOAuthButton = ({ handleOAuth, status }) => { + const [text, setText] = useState(""); + useEffect(() => { + if (status === "success") { + setText("Authenticated"); + return; + } + setText("Sign in with Google"); + }, [status]); + + return ( +
+ + {text} + +
+ ); +}; + +GoogleOAuthButton.propTypes = { + handleOAuth: PropTypes.func.isRequired, + status: PropTypes.string, +}; + +export default GoogleOAuthButton; diff --git a/frontend/src/components/oauth-ds/oauth-ds/OAuthDs.jsx b/frontend/src/components/oauth-ds/oauth-ds/OAuthDs.jsx new file mode 100644 index 000000000..1477b1460 --- /dev/null +++ b/frontend/src/components/oauth-ds/oauth-ds/OAuthDs.jsx @@ -0,0 +1,81 @@ +import { Typography } from "antd"; +import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; + +import { + O_AUTH_PROVIDERS, + getBaseUrl, + handleException, +} from "../../../helpers/GetStaticData"; +import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate.js"; +import { useAlertStore } from "../../../store/alert-store"; +import GoogleOAuthButton from "../google/GoogleOAuthButton.jsx"; +function OAuthDs({ oAuthProvider, setCacheKey, setStatus }) { + const axiosPrivate = useAxiosPrivate(); + const { setAlertDetails } = useAlertStore(); + + const [oauthStatus, setOAuthStatus] = useState( + localStorage.getItem("oauth-status") + ); + + useEffect(() => { + const handleStorageChange = () => { + const updatedOAuthStatus = localStorage.getItem("oauth-status"); + setOAuthStatus(updatedOAuthStatus); + setStatus(updatedOAuthStatus); + }; + + window.addEventListener("storage", handleStorageChange); + + return () => { + window.removeEventListener("storage", handleStorageChange); + localStorage.removeItem("oauth-status"); + setOAuthStatus(""); + }; + }, []); + + const handleOAuth = async () => { + try { + const requestOptions = { + method: "GET", + url: `/api/v1/oauth/cache-key/${oAuthProvider}`, + }; + + const response = await axiosPrivate(requestOptions); + const cacheKey = response?.data?.cache_key; + const encodedCacheKey = encodeURIComponent(cacheKey); + setCacheKey(cacheKey); + + const baseUrl = getBaseUrl(); + + const url = `${baseUrl}/api/v1/oauth/login/${oAuthProvider}?oauth-key=${encodedCacheKey}`; + + // Open in a new window + window.open( + url, + "_blank", + "toolbar=yes,scrollbars=yes,resizable=yes,top=200,left=500,width=500,height=600" + ); + } catch (err) { + setAlertDetails(handleException(err)); + } + }; + + if (O_AUTH_PROVIDERS["GOOGLE"] === oAuthProvider) { + return ( + <> + + + ); + } + + return Provider not available.; +} + +OAuthDs.propTypes = { + oAuthProvider: PropTypes.string, + setCacheKey: PropTypes.func, + setStatus: PropTypes.func, +}; + +export { OAuthDs }; diff --git a/frontend/src/components/oauth-ds/oauth-status/OAuthStatus.css b/frontend/src/components/oauth-ds/oauth-status/OAuthStatus.css new file mode 100644 index 000000000..3187753d1 --- /dev/null +++ b/frontend/src/components/oauth-ds/oauth-status/OAuthStatus.css @@ -0,0 +1,11 @@ +/* Styles for OAuthStatus */ + +.oauth-status-layout { + width: 100%; +} + +.oauth-status-text { + margin-top: 25px; + font-size: 24px; + font-weight: bold; +} \ No newline at end of file diff --git a/frontend/src/components/oauth-ds/oauth-status/OAuthStatus.jsx b/frontend/src/components/oauth-ds/oauth-status/OAuthStatus.jsx new file mode 100644 index 000000000..41b2860f4 --- /dev/null +++ b/frontend/src/components/oauth-ds/oauth-status/OAuthStatus.jsx @@ -0,0 +1,34 @@ +import { Typography } from "antd"; +import { useLocation } from "react-router-dom"; + +import "./OAuthStatus.css"; + +const SUCCESS = "success"; +const DANGER = "danger"; + +function OAuthStatus() { + const location = useLocation(); + const params = new URLSearchParams(location.search); + const status = params.get("status"); + + localStorage.setItem("oauth-status", status); + + if (status === SUCCESS) { + setTimeout(() => { + window.close(); + }, 1000); + } + + return ( +
+ + {"Authentication " + (status === SUCCESS ? "Successful" : "Failed")} + +
+ ); +} + +export { OAuthStatus }; diff --git a/frontend/src/components/onboard/OnBoard.jsx b/frontend/src/components/onboard/OnBoard.jsx new file mode 100644 index 000000000..50c05c916 --- /dev/null +++ b/frontend/src/components/onboard/OnBoard.jsx @@ -0,0 +1,141 @@ +import { CheckCircleFilled } from "@ant-design/icons"; +import { Button, Card, Col, Layout, Row, Space } from "antd"; +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; + +import logo from "../../assets/UnstractLogoBlack.svg"; +import BgShape from "../../assets/bg_shape.svg"; +import ConnectEmbedding from "../../assets/connect_embedding.svg"; +import ConnectLLM from "../../assets/connect_llm.svg"; +import ConnectVectorDb from "../../assets/connect_vector_db.svg"; +import { useSessionStore } from "../../store/session-store.js"; +import { AddSourceModal } from "../input-output/add-source-modal/AddSourceModal.jsx"; +import { CustomButton } from "../widgets/custom-button/CustomButton.jsx"; +const { Content } = Layout; + +import "./onBoard.css"; +function OnBoard() { + const navigate = useNavigate(); + const { sessionDetails } = useSessionStore(); + const { orgName, adapters } = sessionDetails; + const [openAddSourcesModal, setOpenAddSourcesModal] = useState(false); + const [editItemId, setEditItemId] = useState(null); + const [type, setType] = useState(null); + const homePageUrl = `/${orgName}/etl`; + + useEffect(() => { + if (adapters?.length >= 3) { + navigate(homePageUrl); + } + }, []); + + const steps = [ + { + id: 1, + title: "CONNECT AN LLM", + icon: ConnectLLM, + type: "llm", + description: + "Unstract uses Large Language Models (LLMs) to help structure unstructured data and answer questions from large amounts of unstructured data. We support a wide variety of LLMs from various providers.", + }, + { + id: 2, + title: "CONNECT A VECTOR DATABASE", + icon: ConnectVectorDb, + type: "vector_db", + description: + "Vector Databases can help find chunks of text from unstructured source data. This helps find relevant data that can then be sent to LLMs to answer your questions or to structure unstructured data.", + }, + { + id: 3, + title: "CHOOSE AN EMBEDDING MODEL", + icon: ConnectEmbedding, + type: "embedding", + description: + "Embedding models help semantically map unstructured data so that we can then search and retrieve relevant portions of data when structuring or search such data. The quality of the embedding model can affect the quality of relevant data retrieval.", + }, + ]; + + const showOpenAddSourcesModal = (type) => { + setType(type); + setOpenAddSourcesModal(true); + }; + + const addNewItem = (row, isEdit) => { + navigate(0); + }; + + return ( + <> + +
+ Logo +

+ You're 3 steps away from nirvana +

+ + {steps.map((step, index) => ( + +
+
+
{step.id}
+
+
+ +
+
+ logo bg + Logo +
+ + + +

{step.title}

+

+ {step.description} +

+
+ + + {adapters?.includes(step.type) ? ( +
+ + Configured +
+ ) : ( + + )} + + + + ))} + +
+ navigate(homePageUrl)}> + Complete Later > + +
+ + + + + ); +} + +export { OnBoard }; diff --git a/frontend/src/components/onboard/onBoard.css b/frontend/src/components/onboard/onBoard.css new file mode 100644 index 000000000..1d96ca99f --- /dev/null +++ b/frontend/src/components/onboard/onBoard.css @@ -0,0 +1,102 @@ +.onboard-content { + display: flex; + justify-content: center; + margin-top: 50px; +} + +.uppercase-text { + text-transform: uppercase; + color: #0C355A; + font-family: 'SF Pro Text', sans-serif; + margin-bottom: 50px; +} + +.text-title-style { + color: #0C355A; + font-family: 'SF Pro Text', sans-serif; + font-weight: 700; + margin-block-end: 0em; + margin-block-start: 0em; +} + +.text-description-style { + font-family: 'SF Pro Text', sans-serif; + color: #3D6182; + font-weight: 400; +} + +.card-style { + width: 1000px; + background: #FFFFFF; + box-shadow: 0px 6px 16px 0px #00000014; + margin-bottom: 10px; +} + +.button-style { + background: #FF4D6D; + border: 1px solid #FF4D6D; + box-shadow: 0px 2px 0px 0px #00000005; + color: #FFFFFF; +} + +.landing-logo { + height: 40px; + margin-bottom: 50px; +} + +.circle { + position: absolute; + left: 0%; + top: 50%; + transform: translate(-50%, -50%); + width: 32px; + height: 32px; + border-radius: 50%; + background-color: #90a4b7; + display: flex; + align-items: center; + justify-content: center; +} + +.circle-number { + color: white; + font-family: 'SF Pro Text', sans-serif; +} + +.later-div-style { + align-items: center; + display: flex; + justify-content: right; + margin-top: 25px; +} + +.svg-container { + position: relative; + width: 100px; + height: 100px; +} + +.icon-overlay { + position: absolute; + top: 15px; + left: 0; + z-index: 1; +} + +.icon-bg { + height: 190px; + position: absolute; + top: -35px; + left: -55px; +} + +.configured-icon { + color: #52C41A; + font-size: 24px; + vertical-align: middle; +} + +.configured-text { + margin-left: 8px; + vertical-align: middle; +} \ No newline at end of file diff --git a/frontend/src/components/pipelines-or-deployments/app-deploy/AppDeploy.jsx b/frontend/src/components/pipelines-or-deployments/app-deploy/AppDeploy.jsx new file mode 100644 index 000000000..412df7531 --- /dev/null +++ b/frontend/src/components/pipelines-or-deployments/app-deploy/AppDeploy.jsx @@ -0,0 +1,92 @@ +import { ScheduleOutlined } from "@ant-design/icons"; +import { Button, Input, Modal, Select, Space } from "antd"; +import Typography from "antd/es/typography/Typography"; +import PropTypes from "prop-types"; + +import { ToolInfoCard } from "../../agency/tool-info-card/ToolInfoCard"; +import "../etl-task-deploy/EtlTaskDeploy.css"; + +const AppDeploy = ({ open, setOpen }) => { + const { Option } = Select; + const { TextArea } = Input; + + return ( + setOpen(false)} + onCancel={() => setOpen(false)} + okText="Save and Deploy" + okButtonProps={{ style: { background: "#092C4C" } }} + width={800} + closable={true} + maskClosable={false} + > +
+
+ Project Name + +
+ Workflow + +
+ Frequency of runs +