From 7b9847d4f7ce4b277e57cc833157c40515dd0a16 Mon Sep 17 00:00:00 2001 From: Will Cunningham Date: Tue, 25 Jan 2022 09:10:05 -0500 Subject: [PATCH] Covalent Beta Release --- .flake8 | 25 + .github/workflows/badges.yml | 68 + .github/workflows/condabuild.yml | 49 + .github/workflows/publish.yml | 65 + .github/workflows/publish_develop.yml | 34 + .github/workflows/publish_master.yml | 34 + .github/workflows/push_to_s3.yml | 42 + .github/workflows/release.yml | 65 + .github/workflows/tests.yml | 105 + .github/workflows/version.yml | 93 + .gitignore | 125 + .pre-commit-config.yaml | 51 + .prettierrc | 1 + .pylintrc | 561 ++++ .readthedocs.yaml | 44 + CHANGELOG.md | 975 +++++++ CONTRIBUTING.md | 428 +++ Dockerfile | 29 + LICENSE | 661 +++++ README.md | 206 +- VERSION | 1 + covalent/VERSION | 1 + covalent/__init__.py | 42 + covalent/_results_manager/__init__.py | 23 + covalent/_results_manager/result.py | 478 ++++ covalent/_results_manager/results_manager.py | 202 ++ covalent/_results_manager/utils.py | 43 + covalent/_shared_files/__init__.py | 23 + covalent/_shared_files/config.py | 213 ++ covalent/_shared_files/context_managers.py | 133 + covalent/_shared_files/defaults.py | 93 + covalent/_shared_files/logger.py | 76 + covalent/_shared_files/util_classes.py | 70 + covalent/_shared_files/utils.py | 241 ++ covalent/_workflow/__init__.py | 24 + covalent/_workflow/electron.py | 513 ++++ covalent/_workflow/lattice.py | 416 +++ covalent/_workflow/transport.py | 355 +++ covalent/executor/__init__.py | 235 ++ covalent/executor/base.py | 314 +++ covalent/executor/executor_plugins/local.py | 125 + covalent_dispatcher/__init__.py | 121 + covalent_dispatcher/_cli/__init__.py | 0 covalent_dispatcher/_cli/cli.py | 59 + covalent_dispatcher/_cli/service.py | 396 +++ covalent_dispatcher/_core/__init__.py | 429 +++ covalent_dispatcher/_service/app.py | 72 + covalent_ui/README.md | 32 + covalent_ui/__init__.py | 0 covalent_ui/app.py | 137 + covalent_ui/result_webhook.py | 67 + covalent_ui/webapp/.env.development | 2 + covalent_ui/webapp/.env.production | 1 + covalent_ui/webapp/.gitignore | 26 + covalent_ui/webapp/.prettierrc | 4 + covalent_ui/webapp/README.md | 32 + .../webapp/build-demo/asset-manifest.json | 22 + covalent_ui/webapp/build-demo/index.html | 1 + covalent_ui/webapp/build-demo/logo192.png | Bin 0 -> 6781 bytes covalent_ui/webapp/build-demo/manifest.json | 15 + covalent_ui/webapp/build-demo/robots.txt | 3 + .../static/css/main.5658d761.chunk.css | 2 + .../static/css/main.5658d761.chunk.css.map | 1 + .../build-demo/static/js/2.3688fcc7.chunk.js | 3 + .../static/js/2.3688fcc7.chunk.js.LICENSE.txt | 105 + .../static/js/2.3688fcc7.chunk.js.map | 1 + .../static/js/main.deea35c5.chunk.js | 2 + .../static/js/main.deea35c5.chunk.js.map | 1 + .../static/js/runtime-main.533164ea.js | 2 + .../static/js/runtime-main.533164ea.js.map | 1 + .../build-demo/static/media/atom.620f45ef.svg | 15 + .../media/covalent-full-logo.c0b996e7.svg | 115 + covalent_ui/webapp/build/asset-manifest.json | 22 + covalent_ui/webapp/build/index.html | 1 + covalent_ui/webapp/build/logo192.png | Bin 0 -> 6781 bytes covalent_ui/webapp/build/manifest.json | 15 + covalent_ui/webapp/build/robots.txt | 3 + .../build/static/css/main.5658d761.chunk.css | 2 + .../static/css/main.5658d761.chunk.css.map | 1 + .../build/static/js/2.3688fcc7.chunk.js | 3 + .../static/js/2.3688fcc7.chunk.js.LICENSE.txt | 105 + .../build/static/js/2.3688fcc7.chunk.js.map | 1 + .../build/static/js/main.01941850.chunk.js | 2 + .../static/js/main.01941850.chunk.js.map | 1 + .../build/static/js/runtime-main.533164ea.js | 2 + .../static/js/runtime-main.533164ea.js.map | 1 + .../build/static/media/atom.3f8fd5bf.svg | 15 + .../media/covalent-full-logo.b42305d7.svg | 115 + covalent_ui/webapp/package.json | 59 + covalent_ui/webapp/public/index.html | 77 + covalent_ui/webapp/public/logo192.png | Bin 0 -> 6781 bytes covalent_ui/webapp/public/manifest.json | 15 + covalent_ui/webapp/public/robots.txt | 3 + covalent_ui/webapp/src/App.css | 51 + covalent_ui/webapp/src/App.js | 76 + covalent_ui/webapp/src/App.test.js | 30 + covalent_ui/webapp/src/assets/atom.svg | 15 + .../webapp/src/assets/covalent-full-logo.svg | 115 + .../webapp/src/components/CopyButton.js | 52 + .../webapp/src/components/Dashboard.js | 103 + .../webapp/src/components/LogOutput.js | 65 + covalent_ui/webapp/src/components/NodeInfo.js | 112 + covalent_ui/webapp/src/components/Result.js | 213 ++ .../src/components/SyntaxHighlighter.js | 50 + covalent_ui/webapp/src/components/Title.js | 33 + .../src/components/graph/DirectedEdge.js | 38 + .../src/components/graph/ElectronNode.js | 122 + .../webapp/src/components/graph/Layout.js | 173 ++ .../src/components/graph/ParameterNode.js | 57 + .../webapp/src/components/result/Heading.js | 34 + .../src/components/result/LatticeControls.js | 132 + .../src/components/result/LatticeDrawer.js | 189 ++ .../src/components/result/LatticeMain.js | 106 + .../src/components/result/LatticeOverview.js | 92 + .../src/components/result/NodeDrawer.js | 173 ++ .../src/components/result/ResultLayout.js | 150 + .../src/components/results/ResultListing.js | 436 +++ .../src/components/results/ResultProgress.js | 85 + .../webapp/src/components/results/Runtime.js | 88 + covalent_ui/webapp/src/index.js | 42 + covalent_ui/webapp/src/redux/reducers.js | 29 + covalent_ui/webapp/src/redux/resultsSlice.js | 75 + covalent_ui/webapp/src/redux/store.js | 46 + covalent_ui/webapp/src/setupTests.js | 27 + covalent_ui/webapp/src/utils/api.js | 42 + covalent_ui/webapp/src/utils/demo.js | 391 +++ covalent_ui/webapp/src/utils/misc.js | 67 + covalent_ui/webapp/src/utils/socket.js | 52 + covalent_ui/webapp/src/utils/theme.js | 129 + doc/Makefile | 41 + doc/generate_docs.py | 46 + doc/requirements.txt | 25 + doc/source/_static/AQ_Header.png | Bin 0 -> 97442 bytes doc/source/_static/Agnostiq_Logo_dark.png | Bin 0 -> 536011 bytes doc/source/_static/Agnostiq_Logo_white.png | Bin 0 -> 524076 bytes doc/source/_static/covalent.svg | 519 ++++ doc/source/_static/dark.png | Bin 0 -> 12412 bytes doc/source/_static/favcon.png | Bin 0 -> 212632 bytes doc/source/_static/light.png | Bin 0 -> 12209 bytes doc/source/_static/screenshot.png | Bin 0 -> 5413741 bytes doc/source/_static/uibanner.png | Bin 0 -> 5401843 bytes .../_static/undraw_user_flow_re_bvfx.svg | 1 + .../_templates/custom-class-template.rst | 32 + .../_templates/custom-module-template.rst | 67 + doc/source/api/api.rst | 67 + doc/source/concepts/concepts.rst | 465 ++++ .../concepts/images/electron_datatypes.png | Bin 0 -> 26590 bytes .../concepts/images/parallel_lattice.png | Bin 0 -> 26491 bytes doc/source/concepts/images/simple_lattice.png | Bin 0 -> 9511 bytes .../images/single_electron_lattice.png | Bin 0 -> 6649 bytes doc/source/concepts/images/status_check.png | Bin 0 -> 226287 bytes doc/source/concepts/images/sublattice.png | Bin 0 -> 44164 bytes .../concepts/images/transport_graph.png | Bin 0 -> 127066 bytes doc/source/concepts/sublattice.rst | 0 doc/source/conf.py | 103 + doc/source/covalent_theme/LICENSE | 8 + doc/source/covalent_theme/comments.html | 16 + doc/source/covalent_theme/footer.html | 11 + doc/source/covalent_theme/globaltoc.html | 12 + doc/source/covalent_theme/header.html | 147 + doc/source/covalent_theme/layout.html | 287 ++ doc/source/covalent_theme/localtoc.html | 28 + doc/source/covalent_theme/logo-text.html | 0 doc/source/covalent_theme/search.html | 32 + doc/source/covalent_theme/searchbox.html | 15 + doc/source/covalent_theme/sourcelink.html | 12 + doc/source/covalent_theme/static/covalent.css | 2446 +++++++++++++++++ .../covalent_theme/static/css/dark-mode.css | 234 ++ doc/source/covalent_theme/static/jquery.js | 5 + .../covalent_theme/static/jquery.min.map | 1 + .../covalent_theme/static/js/bootstrap.js | 1951 +++++++++++++ .../covalent_theme/static/js/bootstrap.min.js | 6 + .../static/js/dark-mode-switch.min.js | 6 + .../static/js/jquery.nanoscroller.js.map | 10 + .../static/js/nanoscroller.min.js | 4 + .../static/silka/silka-bold-webfont.woff | Bin 0 -> 39540 bytes .../static/silka/silka-medium-webfont.woff | Bin 0 -> 39100 bytes .../static/silka/silka-regular-webfont.woff | Bin 0 -> 37904 bytes doc/source/covalent_theme/static/tomorrow.css | 65 + .../covalent_theme/static/tomorrow_night.css | 67 + doc/source/covalent_theme/theme.conf | 44 + doc/source/extensions/sphinx_execute_code.py | 167 ++ .../getting_started/hello_covalent_graph.png | Bin 0 -> 81125 bytes .../getting_started/hello_covalent_queue.png | Bin 0 -> 42138 bytes doc/source/getting_started/index.rst | 208 ++ .../query_electron_execution_result.ipynb | 101 + .../query_lattice_execution_result.ipynb | 116 + ...y_multiple_lattice_execution_results.ipynb | 149 + doc/source/how_to/config/customization.ipynb | 308 +++ .../how_to/execution/cancel_dispatch.ipynb | 203 ++ .../choosing_conda_environments.ipynb | 185 ++ .../how_to/execution/choosing_executors.ipynb | 185 ++ doc/source/how_to/execution/covalent_cli.rst | 62 + .../execute_individual_electron.ipynb | 83 + .../how_to/execution/execute_lattice.ipynb | 102 + .../execution/execute_multiple_lattices.ipynb | 112 + .../how_to/execution/execute_sublattice.ipynb | 252 ++ .../execution/synchronize_lattice.ipynb | 89 + doc/source/how_to/index.rst | 51 + .../add_constraints_to_lattice.ipynb | 80 + .../add_electron_to_lattice.ipynb | 77 + .../orchestration/construct_electron.ipynb | 81 + .../orchestration/construct_lattice.ipynb | 61 + .../orchestration/visualize_lattice.ipynb | 105 + .../query_electron_execution_status.ipynb | 154 ++ .../query_lattice_execution_status.ipynb | 152 + .../status/query_lattice_execution_time.ipynb | 91 + doc/source/index.rst | 127 + .../tutorials/astronomy/star_tracker.ipynb | 427 +++ .../classical_quantum_svm.ipynb | 319 +++ .../nitrogen_copper_interaction.ipynb | 505 ++++ .../quantum_gravity/qg_workflow_1.png | Bin 0 -> 174918 bytes .../quantum_gravity/qg_workflow_3.png | Bin 0 -> 296969 bytes .../spacetime_classification.ipynb | 810 ++++++ doc/source/tutorials/tutorials.rst | 16 + meta.yaml | 71 + pyproject.toml | 39 + requirements.txt | 14 + setup.py | 129 +- tests/__init__.py | 0 tests/covalent_dispatcher_tests/__init__.py | 0 .../_core/init_test.py | 25 + .../choose_conda_test.py | 53 + tests/covalent_dispatcher_tests/data.py | 102 + .../dispatcher_stack_test.py | 68 + tests/covalent_dispatcher_tests/init_test.py | 57 + tests/covalent_tests/choose_executor_test.py | 78 + .../covalent_tests/workflow/transport_test.py | 256 ++ tests/electron_return_value_test.py | 173 ++ tests/functional_tests/__init__.py | 0 .../functional_tests/basic_dispatcher_test.py | 99 + .../dispatcher_server_test.py | 57 + tests/functional_tests/docs_how_to_test.py | 51 + tests/functional_tests/serialization_test.py | 147 + tests/requirements.txt | 9 + tests/workflow_stack_test.py | 328 +++ 236 files changed, 26976 insertions(+), 13 deletions(-) create mode 100644 .flake8 create mode 100644 .github/workflows/badges.yml create mode 100644 .github/workflows/condabuild.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/publish_develop.yml create mode 100644 .github/workflows/publish_master.yml create mode 100644 .github/workflows/push_to_s3.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/tests.yml create mode 100644 .github/workflows/version.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 .prettierrc create mode 100644 .pylintrc create mode 100644 .readthedocs.yaml create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 VERSION create mode 100644 covalent/VERSION create mode 100644 covalent/_results_manager/__init__.py create mode 100644 covalent/_results_manager/result.py create mode 100644 covalent/_results_manager/results_manager.py create mode 100644 covalent/_results_manager/utils.py create mode 100644 covalent/_shared_files/__init__.py create mode 100644 covalent/_shared_files/config.py create mode 100644 covalent/_shared_files/context_managers.py create mode 100644 covalent/_shared_files/defaults.py create mode 100644 covalent/_shared_files/logger.py create mode 100644 covalent/_shared_files/util_classes.py create mode 100644 covalent/_shared_files/utils.py create mode 100644 covalent/_workflow/__init__.py create mode 100644 covalent/_workflow/electron.py create mode 100644 covalent/_workflow/lattice.py create mode 100644 covalent/_workflow/transport.py create mode 100644 covalent/executor/__init__.py create mode 100644 covalent/executor/base.py create mode 100644 covalent/executor/executor_plugins/local.py create mode 100644 covalent_dispatcher/__init__.py create mode 100644 covalent_dispatcher/_cli/__init__.py create mode 100644 covalent_dispatcher/_cli/cli.py create mode 100644 covalent_dispatcher/_cli/service.py create mode 100644 covalent_dispatcher/_core/__init__.py create mode 100644 covalent_dispatcher/_service/app.py create mode 100644 covalent_ui/README.md create mode 100644 covalent_ui/__init__.py create mode 100644 covalent_ui/app.py create mode 100644 covalent_ui/result_webhook.py create mode 100644 covalent_ui/webapp/.env.development create mode 100644 covalent_ui/webapp/.env.production create mode 100644 covalent_ui/webapp/.gitignore create mode 100644 covalent_ui/webapp/.prettierrc create mode 100644 covalent_ui/webapp/README.md create mode 100644 covalent_ui/webapp/build-demo/asset-manifest.json create mode 100644 covalent_ui/webapp/build-demo/index.html create mode 100644 covalent_ui/webapp/build-demo/logo192.png create mode 100644 covalent_ui/webapp/build-demo/manifest.json create mode 100644 covalent_ui/webapp/build-demo/robots.txt create mode 100644 covalent_ui/webapp/build-demo/static/css/main.5658d761.chunk.css create mode 100644 covalent_ui/webapp/build-demo/static/css/main.5658d761.chunk.css.map create mode 100644 covalent_ui/webapp/build-demo/static/js/2.3688fcc7.chunk.js create mode 100644 covalent_ui/webapp/build-demo/static/js/2.3688fcc7.chunk.js.LICENSE.txt create mode 100644 covalent_ui/webapp/build-demo/static/js/2.3688fcc7.chunk.js.map create mode 100644 covalent_ui/webapp/build-demo/static/js/main.deea35c5.chunk.js create mode 100644 covalent_ui/webapp/build-demo/static/js/main.deea35c5.chunk.js.map create mode 100644 covalent_ui/webapp/build-demo/static/js/runtime-main.533164ea.js create mode 100644 covalent_ui/webapp/build-demo/static/js/runtime-main.533164ea.js.map create mode 100644 covalent_ui/webapp/build-demo/static/media/atom.620f45ef.svg create mode 100644 covalent_ui/webapp/build-demo/static/media/covalent-full-logo.c0b996e7.svg create mode 100644 covalent_ui/webapp/build/asset-manifest.json create mode 100644 covalent_ui/webapp/build/index.html create mode 100644 covalent_ui/webapp/build/logo192.png create mode 100644 covalent_ui/webapp/build/manifest.json create mode 100644 covalent_ui/webapp/build/robots.txt create mode 100644 covalent_ui/webapp/build/static/css/main.5658d761.chunk.css create mode 100644 covalent_ui/webapp/build/static/css/main.5658d761.chunk.css.map create mode 100644 covalent_ui/webapp/build/static/js/2.3688fcc7.chunk.js create mode 100644 covalent_ui/webapp/build/static/js/2.3688fcc7.chunk.js.LICENSE.txt create mode 100644 covalent_ui/webapp/build/static/js/2.3688fcc7.chunk.js.map create mode 100644 covalent_ui/webapp/build/static/js/main.01941850.chunk.js create mode 100644 covalent_ui/webapp/build/static/js/main.01941850.chunk.js.map create mode 100644 covalent_ui/webapp/build/static/js/runtime-main.533164ea.js create mode 100644 covalent_ui/webapp/build/static/js/runtime-main.533164ea.js.map create mode 100644 covalent_ui/webapp/build/static/media/atom.3f8fd5bf.svg create mode 100644 covalent_ui/webapp/build/static/media/covalent-full-logo.b42305d7.svg create mode 100644 covalent_ui/webapp/package.json create mode 100644 covalent_ui/webapp/public/index.html create mode 100644 covalent_ui/webapp/public/logo192.png create mode 100644 covalent_ui/webapp/public/manifest.json create mode 100644 covalent_ui/webapp/public/robots.txt create mode 100644 covalent_ui/webapp/src/App.css create mode 100644 covalent_ui/webapp/src/App.js create mode 100644 covalent_ui/webapp/src/App.test.js create mode 100644 covalent_ui/webapp/src/assets/atom.svg create mode 100644 covalent_ui/webapp/src/assets/covalent-full-logo.svg create mode 100644 covalent_ui/webapp/src/components/CopyButton.js create mode 100644 covalent_ui/webapp/src/components/Dashboard.js create mode 100644 covalent_ui/webapp/src/components/LogOutput.js create mode 100644 covalent_ui/webapp/src/components/NodeInfo.js create mode 100644 covalent_ui/webapp/src/components/Result.js create mode 100644 covalent_ui/webapp/src/components/SyntaxHighlighter.js create mode 100644 covalent_ui/webapp/src/components/Title.js create mode 100644 covalent_ui/webapp/src/components/graph/DirectedEdge.js create mode 100644 covalent_ui/webapp/src/components/graph/ElectronNode.js create mode 100644 covalent_ui/webapp/src/components/graph/Layout.js create mode 100644 covalent_ui/webapp/src/components/graph/ParameterNode.js create mode 100644 covalent_ui/webapp/src/components/result/Heading.js create mode 100644 covalent_ui/webapp/src/components/result/LatticeControls.js create mode 100644 covalent_ui/webapp/src/components/result/LatticeDrawer.js create mode 100644 covalent_ui/webapp/src/components/result/LatticeMain.js create mode 100644 covalent_ui/webapp/src/components/result/LatticeOverview.js create mode 100644 covalent_ui/webapp/src/components/result/NodeDrawer.js create mode 100644 covalent_ui/webapp/src/components/result/ResultLayout.js create mode 100644 covalent_ui/webapp/src/components/results/ResultListing.js create mode 100644 covalent_ui/webapp/src/components/results/ResultProgress.js create mode 100644 covalent_ui/webapp/src/components/results/Runtime.js create mode 100644 covalent_ui/webapp/src/index.js create mode 100644 covalent_ui/webapp/src/redux/reducers.js create mode 100644 covalent_ui/webapp/src/redux/resultsSlice.js create mode 100644 covalent_ui/webapp/src/redux/store.js create mode 100644 covalent_ui/webapp/src/setupTests.js create mode 100644 covalent_ui/webapp/src/utils/api.js create mode 100644 covalent_ui/webapp/src/utils/demo.js create mode 100644 covalent_ui/webapp/src/utils/misc.js create mode 100644 covalent_ui/webapp/src/utils/socket.js create mode 100644 covalent_ui/webapp/src/utils/theme.js create mode 100644 doc/Makefile create mode 100644 doc/generate_docs.py create mode 100644 doc/requirements.txt create mode 100644 doc/source/_static/AQ_Header.png create mode 100644 doc/source/_static/Agnostiq_Logo_dark.png create mode 100644 doc/source/_static/Agnostiq_Logo_white.png create mode 100644 doc/source/_static/covalent.svg create mode 100644 doc/source/_static/dark.png create mode 100644 doc/source/_static/favcon.png create mode 100644 doc/source/_static/light.png create mode 100644 doc/source/_static/screenshot.png create mode 100644 doc/source/_static/uibanner.png create mode 100644 doc/source/_static/undraw_user_flow_re_bvfx.svg create mode 100644 doc/source/_templates/custom-class-template.rst create mode 100644 doc/source/_templates/custom-module-template.rst create mode 100644 doc/source/api/api.rst create mode 100644 doc/source/concepts/concepts.rst create mode 100644 doc/source/concepts/images/electron_datatypes.png create mode 100644 doc/source/concepts/images/parallel_lattice.png create mode 100644 doc/source/concepts/images/simple_lattice.png create mode 100644 doc/source/concepts/images/single_electron_lattice.png create mode 100644 doc/source/concepts/images/status_check.png create mode 100644 doc/source/concepts/images/sublattice.png create mode 100644 doc/source/concepts/images/transport_graph.png create mode 100644 doc/source/concepts/sublattice.rst create mode 100644 doc/source/conf.py create mode 100644 doc/source/covalent_theme/LICENSE create mode 100644 doc/source/covalent_theme/comments.html create mode 100644 doc/source/covalent_theme/footer.html create mode 100644 doc/source/covalent_theme/globaltoc.html create mode 100644 doc/source/covalent_theme/header.html create mode 100644 doc/source/covalent_theme/layout.html create mode 100644 doc/source/covalent_theme/localtoc.html create mode 100644 doc/source/covalent_theme/logo-text.html create mode 100644 doc/source/covalent_theme/search.html create mode 100644 doc/source/covalent_theme/searchbox.html create mode 100644 doc/source/covalent_theme/sourcelink.html create mode 100644 doc/source/covalent_theme/static/covalent.css create mode 100644 doc/source/covalent_theme/static/css/dark-mode.css create mode 100644 doc/source/covalent_theme/static/jquery.js create mode 100755 doc/source/covalent_theme/static/jquery.min.map create mode 100644 doc/source/covalent_theme/static/js/bootstrap.js create mode 100755 doc/source/covalent_theme/static/js/bootstrap.min.js create mode 100644 doc/source/covalent_theme/static/js/dark-mode-switch.min.js create mode 100644 doc/source/covalent_theme/static/js/jquery.nanoscroller.js.map create mode 100644 doc/source/covalent_theme/static/js/nanoscroller.min.js create mode 100755 doc/source/covalent_theme/static/silka/silka-bold-webfont.woff create mode 100755 doc/source/covalent_theme/static/silka/silka-medium-webfont.woff create mode 100755 doc/source/covalent_theme/static/silka/silka-regular-webfont.woff create mode 100644 doc/source/covalent_theme/static/tomorrow.css create mode 100644 doc/source/covalent_theme/static/tomorrow_night.css create mode 100644 doc/source/covalent_theme/theme.conf create mode 100644 doc/source/extensions/sphinx_execute_code.py create mode 100644 doc/source/getting_started/hello_covalent_graph.png create mode 100644 doc/source/getting_started/hello_covalent_queue.png create mode 100644 doc/source/getting_started/index.rst create mode 100644 doc/source/how_to/collection/query_electron_execution_result.ipynb create mode 100644 doc/source/how_to/collection/query_lattice_execution_result.ipynb create mode 100644 doc/source/how_to/collection/query_multiple_lattice_execution_results.ipynb create mode 100644 doc/source/how_to/config/customization.ipynb create mode 100644 doc/source/how_to/execution/cancel_dispatch.ipynb create mode 100644 doc/source/how_to/execution/choosing_conda_environments.ipynb create mode 100644 doc/source/how_to/execution/choosing_executors.ipynb create mode 100644 doc/source/how_to/execution/covalent_cli.rst create mode 100644 doc/source/how_to/execution/execute_individual_electron.ipynb create mode 100644 doc/source/how_to/execution/execute_lattice.ipynb create mode 100644 doc/source/how_to/execution/execute_multiple_lattices.ipynb create mode 100644 doc/source/how_to/execution/execute_sublattice.ipynb create mode 100644 doc/source/how_to/execution/synchronize_lattice.ipynb create mode 100644 doc/source/how_to/index.rst create mode 100644 doc/source/how_to/orchestration/add_constraints_to_lattice.ipynb create mode 100644 doc/source/how_to/orchestration/add_electron_to_lattice.ipynb create mode 100644 doc/source/how_to/orchestration/construct_electron.ipynb create mode 100644 doc/source/how_to/orchestration/construct_lattice.ipynb create mode 100644 doc/source/how_to/orchestration/visualize_lattice.ipynb create mode 100644 doc/source/how_to/status/query_electron_execution_status.ipynb create mode 100644 doc/source/how_to/status/query_lattice_execution_status.ipynb create mode 100644 doc/source/how_to/status/query_lattice_execution_time.ipynb create mode 100644 doc/source/index.rst create mode 100644 doc/source/tutorials/astronomy/star_tracker.ipynb create mode 100644 doc/source/tutorials/machine_learning/classical_quantum_svm.ipynb create mode 100644 doc/source/tutorials/quantum_chemistry/nitrogen_copper_interaction.ipynb create mode 100644 doc/source/tutorials/quantum_gravity/qg_workflow_1.png create mode 100644 doc/source/tutorials/quantum_gravity/qg_workflow_3.png create mode 100644 doc/source/tutorials/quantum_gravity/spacetime_classification.ipynb create mode 100644 doc/source/tutorials/tutorials.rst create mode 100644 meta.yaml create mode 100644 pyproject.toml create mode 100644 requirements.txt create mode 100644 tests/__init__.py create mode 100644 tests/covalent_dispatcher_tests/__init__.py create mode 100644 tests/covalent_dispatcher_tests/_core/init_test.py create mode 100644 tests/covalent_dispatcher_tests/choose_conda_test.py create mode 100644 tests/covalent_dispatcher_tests/data.py create mode 100644 tests/covalent_dispatcher_tests/dispatcher_stack_test.py create mode 100644 tests/covalent_dispatcher_tests/init_test.py create mode 100644 tests/covalent_tests/choose_executor_test.py create mode 100644 tests/covalent_tests/workflow/transport_test.py create mode 100644 tests/electron_return_value_test.py create mode 100644 tests/functional_tests/__init__.py create mode 100644 tests/functional_tests/basic_dispatcher_test.py create mode 100644 tests/functional_tests/dispatcher_server_test.py create mode 100644 tests/functional_tests/docs_how_to_test.py create mode 100644 tests/functional_tests/serialization_test.py create mode 100644 tests/requirements.txt create mode 100644 tests/workflow_stack_test.py diff --git a/.flake8 b/.flake8 new file mode 100644 index 000000000..737cbd690 --- /dev/null +++ b/.flake8 @@ -0,0 +1,25 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +[flake8] +max-line-length = 99 +max-complexity = 18 +select = B,C,E,F,W,T4,B9 +ignore = E501, E722, W503, F401, F403, F811, F841, E203 diff --git a/.github/workflows/badges.yml b/.github/workflows/badges.yml new file mode 100644 index 000000000..97d9307d5 --- /dev/null +++ b/.github/workflows/badges.yml @@ -0,0 +1,68 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +name: badges + +on: + push: + branches: + - master + +jobs: + badges: + runs-on: ubuntu-latest + steps: + - name: Check out master + uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install Python dependencies + run: | + python -m pip install --upgrade pip + pip install anybadge pylint + mkdir -p badges + - name: Read version + run: | + VERSION="$(cat ./VERSION)" + echo "VERSION=$VERSION" >> $GITHUB_ENV + - name: Generate version badge + run: anybadge -l "version" -v $VERSION -c navy -f badges/version.svg + - name: Generate platform badge + run: anybadge -l "platform" -v "linux-64" -c gray -f badges/platform.svg + - name: Run linter + run: | + pylint covalent covalent_dispatcher --output-format=text --exit-zero | tee pylint.txt + SCORE=$(sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' pylint.txt) + echo "Pylint score was $SCORE" + anybadge -l "pylint" -v $SCORE -f badges/pylint.svg 2=red 4=orange 7=yellow 9=green + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + - name: Upload to S3 + run: | + aws s3 sync ./badges/ ${{ secrets.AWS_BADGE_BUCKET }} \ + --delete \ + --cache-control no-cache \ + --acl public-read diff --git a/.github/workflows/condabuild.yml b/.github/workflows/condabuild.yml new file mode 100644 index 000000000..ff36fe9fb --- /dev/null +++ b/.github/workflows/condabuild.yml @@ -0,0 +1,49 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +name: conda + +on: + push: + branches-ignore: + - develop + - master + +jobs: + conda: + runs-on: ubuntu-latest + steps: + - name: Check out head + uses: actions/checkout@v1 + with: + fetch-depth: 0 + - name: Check for build change + id: buildchange + run: git diff --name-only origin/develop | grep -e setup.py -e requirements.txt -e meta.yaml + continue-on-error: true + - name: Build conda package + if: steps.buildchange.outcome == 'success' + run: | + conda install conda-build conda-verify + conda config --append channels conda-forge + conda create --name buildenv python=3.8 + $CONDA/bin/activate buildenv + conda build --override-channels . + diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 000000000..c7ec6ab88 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,65 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +name: publish + +on: + workflow_call: + secrets: + aws_ecr_repo: + required: true + aws_key_id: + required: true + aws_secret_access_key: + required: true + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - name: Check out head + uses: actions/checkout@v2 + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.aws_key_id }} + aws-secret-access-key: ${{ secrets.aws_secret_access_key }} + aws-region: us-east-1 + - name: Login to ECR + uses: aws-actions/amazon-ecr-login@v1 + - name: Generate tag + run: | + aws --version + docker info + docker --version + TAG="$(cat ./VERSION)" + if aws ecr describe-images \ + --repository-name covalent \ + --image-ids imageTag=$TAG &> /dev/null ; then + SHORT_SHA="${GITHUB_SHA::8}" + TAG=$TAG-$SHORT_SHA + fi + echo "TAG=$TAG" >> $GITHUB_ENV + - name: Build and push image + run: | + docker build -t ${{ secrets.aws_ecr_repo }} . + docker push ${{ secrets.aws_ecr_repo }} + docker tag ${{ secrets.aws_ecr_repo }} ${{ secrets.aws_ecr_repo }}:$TAG + docker push ${{ secrets.aws_ecr_repo }}:$TAG diff --git a/.github/workflows/publish_develop.yml b/.github/workflows/publish_develop.yml new file mode 100644 index 000000000..23c7e29f9 --- /dev/null +++ b/.github/workflows/publish_develop.yml @@ -0,0 +1,34 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +name: Release Development Docker Image to ECR + +on: + push: + branches: + - develop + +jobs: + publish_develop: + uses: AgnostiqHQ/covalent/.github/workflows/publish.yml@develop + secrets: + aws_ecr_repo: ${{ secrets.AWS_ECR_DEV_REPO }} + aws_key_id: ${{ secrets.AWS_KEY_ID }} + aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/publish_master.yml b/.github/workflows/publish_master.yml new file mode 100644 index 000000000..6d9d7a353 --- /dev/null +++ b/.github/workflows/publish_master.yml @@ -0,0 +1,34 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +name: Release Docker Image to ECR + +on: + push: + branches: + - master + +jobs: + publish_master: + uses: AgnostiqHQ/covalent/.github/workflows/publish.yml@develop + secrets: + aws_ecr_repo: ${{ secrets.AWS_ECR_REPO }} + aws_key_id: ${{ secrets.AWS_KEY_ID }} + aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/push_to_s3.yml b/.github/workflows/push_to_s3.yml new file mode 100644 index 000000000..00a302187 --- /dev/null +++ b/.github/workflows/push_to_s3.yml @@ -0,0 +1,42 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +name: push-to-s3 + +on: + push: + branches: + - develop + - develop-ui + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - name: Check out head + uses: actions/checkout@v2 + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + - name: Deploy static site to S3 bucket + run: aws s3 sync ./covalent_ui/webapp/build-demo/ ${{ secrets.S3_STATIC }} --delete diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..39898417c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,65 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +name: release + +on: + push: + branches: + - master + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Check out master + uses: actions/checkout@v2 + with: + persist-credentials: false + fetch-depth: 0 + - name: Read version + run: | + VERSION="$(cat ./VERSION)" + echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "RELEASE=v$VERSION" >> $GITHUB_ENV + - name: Tag commit + id: push + run: | + git config user.name "CovalentOpsBot" + git config user.email "covalentopsbot@users.noreply.github.com" + git tag -a $RELEASE -m "Release $RELEASE" + git remote set-url origin https://${{ secrets.COVALENT_OPS_BOT_TOKEN }}@github.com/AgnostiqHQ/covalent.git + git push origin $RELEASE + - name: Generate release message + id: message + run: | + begin=$(grep -n "\b${VERSION}\b" ./CHANGELOG.md | cut -d ':' -f 1) + previous_version=$(git describe --abbrev=0 $RELEASE^ | cut -c2-) + end=$(tail -n +$((begin+1)) ./CHANGELOG.md | grep -n -m 1 "\b${previous_version}\b" | cut -d ':' -f 1) + echo 'MESSAGE<> $GITHUB_ENV + tail +$begin ./CHANGELOG.md | head -$end >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV + - name: Create release + if: ${{ steps.push.outcome == 'success' && steps.message.outcome == 'success' }} + uses: ncipollo/release-action@v1 + with: + body: ${{ env.MESSAGE }} + token: ${{ secrets.COVALENT_OPS_BOT_TOKEN }} + tag: ${{ env.RELEASE }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..40a15a7db --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,105 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +name: tests + +on: + push: + branches-ignore: + - master + +jobs: + tests: + runs-on: ubuntu-latest + steps: +# - name: Start notification +# uses: rtCamp/action-slack-notify@v2 +# env: +# SLACK_CHANNEL: "covalent-ci" +# SLACK_USERNAME: "CovalentOpsBot" +# SLACK_MESSAGE: "Test started by push." +# SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} +# SLACK_COLOR: "#808080" + - name: Check out head + uses: actions/checkout@v2 + with: + persist-credentials: false + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install Python dependencies + run: | + python -m pip install --upgrade pip + pip install --no-cache-dir -r ./requirements.txt + pip install --no-cache-dir -r ./tests/requirements.txt + - name: Install Covalent + run: pip install -e . + - name: Start Covalent dispatcher server + run: covalent start -d + - name: Run tests and measure coverage + run: pytest -v --cov=covalent --cov=covalent_dispatcher +# - name: Notify success +# if: success() +# uses: rtCamp/action-slack-notify@v2 +# env: +# SLACK_CHANNEL: "covalent-ci" +# SLACK_USERNAME: "CovalentOpsBot" +# SLACK_MESSAGE: "Test succeeded." +# SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} +# SLACK_COLOR: ${{ job.status }} +# - name: Notify failure +# if: failure() +# uses: rtCamp/action-slack-notify@v2 +# env: +# SLACK_CHANNEL: "covalent-ci" +# SLACK_USERNAME: "CovalentOpsBot" +# SLACK_MESSAGE: "Test failed." +# SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} +# SLACK_COLOR: ${{ job.status }} + - name: Generate coverage report + run: coverage xml + - name: Upload report to Codecov + uses: codecov/codecov-action@v2 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage.xml + - name: Push to master + if: github.ref == 'refs/heads/develop' + run: | + git config user.name "CovalentOpsBot" + git config user.email "covalentopsbot@users.noreply.github.com" + git remote set-url origin https://${{ secrets.COVALENT_OPS_BOT_TOKEN }}@github.com/AgnostiqHQ/covalent.git + git fetch --unshallow + git push origin HEAD:master +# - name: Format Slack message +# if: github.ref == 'refs/heads/develop' +# run: | +# VERSION="$(cat ./VERSION)" +# SLACK_MSG=":rocket: Version $VERSION is now available." +# echo "SLACK_MSG=$SLACK_MSG" >> $GITHUB_ENV +# - name: Notify Slack +# if: github.ref == 'refs/heads/develop' +# uses: rtCamp/action-slack-notify@v2 +# env: +# SLACK_CHANNEL: "covalent-ci" +# SLACK_USERNAME: "CovalentOpsBot" +# SLACK_MESSAGE: ${{ env.SLACK_MSG }} +# SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml new file mode 100644 index 000000000..306e4b6fd --- /dev/null +++ b/.github/workflows/version.yml @@ -0,0 +1,93 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +name: version + +on: + push: + branches-ignore: + - develop + - master + +jobs: + version: + runs-on: ubuntu-latest + env: + SEMVER_REGEX: '[0-9]+\.[0-9]+\.[0-9]+' + steps: + - name: Check out head + uses: actions/checkout@v1 + with: + fetch-depth: 0 + - name: Read head version + run: | + HEAD_VERSION="$(cat ./VERSION)" + echo "HEAD_VERSION=$HEAD_VERSION" >> $GITHUB_ENV + - name: Validate changelog entry + run: | + git diff --name-only origin/develop | grep CHANGELOG + if [[ $(grep -c "\b${HEAD_VERSION}\b" CHANGELOG.md) > 1 ]]; then + echo 'There are duplicate entries in the changelog.' + exit 4 + elif [[ $(grep -c "\b${HEAD_VERSION}\b" CHANGELOG.md) < 1 ]]; then + echo "There is not a changelog entry that matches the head version ${HEAD_VERSION}." + exit 5 + fi + changedate=$(grep "\b${HEAD_VERSION}\b" CHANGELOG.md | awk '{ print $4 }') + date -I -d $changedate + if [[ $changedate > $(date -I) ]] || + [[ $changedate < $(date -I --date='-1 year') ]] ; then + echo "There is a problem with the date in the changelog." + exit 3 + fi + - name: Check out base + run: git checkout develop + - name: Read base version + run: | + BASE_VERSION="$(cat ./VERSION)" + echo "BASE_VERSION=$BASE_VERSION" >> $GITHUB_ENV + - name: Validate version change + run: | + echo "head version is ${HEAD_VERSION}" + echo "base version is ${BASE_VERSION}" + if [[ $BASE_VERSION =~ $SEMVER_REGEX ]] && + [[ $HEAD_VERSION =~ $SEMVER_REGEX ]] && + dpkg --compare-versions $HEAD_VERSION 'gt' $BASE_VERSION ; then + echo "Validated version incremented correctly." + exit 0 + elif [[ $BASE_VERSION =~ $SEMVER_REGEX ]] && + [[ $HEAD_VERSION =~ $SEMVER_REGEX ]] ; then + echo "You must increment the version to merge this branch." + exit 1 + elif [[ $BASE_VERSION =~ $SEMVER_REGEX ]] ; then + echo "The version number in this branch is not a valid semantic version." + exit 2 + else + echo "Pass due to bad version format in develop branch." + fi +# - name: Notify failure +# if: failure() +# uses: rtCamp/action-slack-notify@v2 +# env: +# SLACK_CHANNEL: "covalent-ci" +# SLACK_USERNAME: "CovalentOpsBot" +# SLACK_MESSAGE: "Failed to validate version or changelog." +# SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} +# SLACK_COLOR: ${{ job.status }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..c6a56bf14 --- /dev/null +++ b/.gitignore @@ -0,0 +1,125 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +# Ignore results folderss +**/results/** +**/result_* +!covalent_ui/result_webhook.py + +*.xml + +# pickle files +*.pkl + +# egg info +**.egg-info/** + +# sqlite +data_cache.sqlite + +# mac +**/.DS_Store +**/.idea + +# Visual Studio +*.vscode + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# Jupyter Notebook +*.ipynb_checkpoints +covalent/**/*.ipynb +covalent/*.ipynb +covalent_dispatcher/**/*.ipynb +covalent_dispatcher/*.ipynb + +# IPython +profile_default/ +ipython_config.py + +# pyenv +*.python-version + +# PEP 582 +__pypackages__/ + +# Environments +*.env +*.ini +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/*. +ipython_config.py + +# Shared libraries +*.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 + +# IPython +profile_default/ +ipython_config.py + +# Dask +**/dask-worker-space/** +*.lock + +# Databases +*.db + +# Coverage +.coverage + +# Temporary files +covalent_dispatcher/_service/tmp* diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..5542fb073 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,51 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +exclude: ".git|.tox" +default_stages: [commit] +fail_fast: true + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.0.1 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-added-large-files + args: ["--maxkb=10000"] + - id: check-merge-conflict + - id: requirements-txt-fixer + + - repo: https://github.com/pre-commit/mirrors-isort + rev: v5.8.0 + hooks: + - id: isort + args: ["--profile", "black"] + + - repo: https://github.com/ambv/black + rev: 21.5b1 + hooks: + - id: black + language_version: python3.8 + + - repo: https://github.com/PyCQA/flake8 + rev: 3.9.2 + hooks: + - id: flake8 diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..f1d7f9082 --- /dev/null +++ b/.prettierrc @@ -0,0 +1 @@ +tabWidth: 4 diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 000000000..1159dfddf --- /dev/null +++ b/.pylintrc @@ -0,0 +1,561 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +extension-pkg-allow-list= + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. (This is an alternative name to extension-pkg-allow-list +# for backward compatibility.) +extension-pkg-whitelist= + +# Return non-zero exit code if any of these messages/categories are detected, +# even if score is above --fail-under value. Syntax same as enable. Messages +# specified are enabled, while categories only check already-enabled messages. +fail-on= + +# Specify a score threshold to be exceeded before program exits with error. +fail-under=10.0 + +# Files or directories to be skipped. They should be base names, not paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the ignore-list. The +# regex matches against paths. +ignore-paths= + +# Files or directories matching the regex patterns are skipped. The regex +# matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use. +jobs=1 + +# Control the amount of potential inferred values when inferring a single +# object. This can help the performance when dealing with large functions or +# complex, nested conditions. +limit-inference-results=100 + +# List of plugins (as comma separated values of python module names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Min Python version to use for version dependend checks. Will default to the +# version used to run pylint. +py-version=3.8 + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=raw-checker-failed, + bad-inline-option, + locally-disabled, + file-ignored, + suppressed-message, + useless-suppression, + deprecated-pragma, + use-symbolic-message-instead, + import-outside-toplevel + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable=c-extension-no-member + + +[REPORTS] + +# Python expression which should return a score less than or equal to 10. You +# have access to the variables 'error', 'warning', 'refactor', and 'convention' +# which contain the number of messages in each category, as well as 'statement' +# which is the total number of statements analyzed. This score is used by the +# global evaluation report (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +#msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages. +reports=no + +# Activate the evaluation score. +score=yes + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit,argparse.parse_error + + +[LOGGING] + +# The type of string formatting that logging methods do. `old` means using % +# formatting, `new` is for `{}` formatting. +logging-format-style=old + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules=logging + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis). It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + +# List of decorators that change the signature of a decorated function. +signature-mutators= + + +[SIMILARITIES] + +# Comments are removed from the similarity computation +ignore-comments=yes + +# Docstrings are removed from the similarity computation +ignore-docstrings=yes + +# Imports are removed from the similarity computation +ignore-imports=no + +# Signatures are removed from the similarity computation +ignore-signatures=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[BASIC] + +# Naming style matching correct argument names. +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style. +#argument-rgx= + +# Naming style matching correct attribute names. +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma. +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Bad variable names regexes, separated by a comma. If names match any regex, +# they will always be refused +bad-names-rgxs= + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. +#class-attribute-rgx= + +# Naming style matching correct class constant names. +class-const-naming-style=UPPER_CASE + +# Regular expression matching correct class constant names. Overrides class- +# const-naming-style. +#class-const-rgx= + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming- +# style. +#class-rgx= + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style. +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style. +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma. +good-names=i, + j, + k, + ex, + Run, + _ + +# Good variable names regexes, separated by a comma. If names match any regex, +# they will always be accepted +good-names-rgxs= + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint=no + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. +#inlinevar-rgx= + +# Naming style matching correct method names. +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style. +#method-rgx= + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style. +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes=abc.abstractproperty + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style. +#variable-rgx= + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of names allowed to shadow builtins +allowed-redefined-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expected to +# not be used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore. +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io + + +[STRING] + +# This flag controls whether inconsistent-quotes generates a warning when the +# character used as a quote delimiter is used inconsistently within a module. +check-quote-consistency=no + +# This flag controls whether the implicit-str-concat should generate a warning +# on implicit string concatenation in sequences defined over several lines. +check-str-concat-over-line-jumps=no + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=100 + +# Maximum number of lines in a module. +max-module-lines=1000 + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + +# Regular expression of note tags to take in consideration. +#notes-rgx= + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: none. To make it work, +# install the 'python-enchant' package. +spelling-dict= + +# List of comma separated words that should be considered directives if they +# appear and the beginning of a comment and should not be checked. +spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains the private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to the private dictionary (see the +# --spelling-private-dict-file option) instead of raising a message. +spelling-store-unknown-words=no + + +[IMPORTS] + +# List of modules that can be imported at any level, not just the top level +# one. +allow-any-import-level= + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules= + +# Output a graph (.gv or any supported image format) of external dependencies +# to the given file (report RP0402 must not be disabled). +ext-import-graph= + +# Output a graph (.gv or any supported image format) of all (i.e. internal and +# external) dependencies to the given file (report RP0402 must not be +# disabled). +import-graph= + +# Output a graph (.gv or any supported image format) of internal dependencies +# to the given file (report RP0402 must not be disabled). +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + +# Couples of modules and preferred modules, separated by a comma. +preferred-modules= + + +[CLASSES] + +# Warn about protected attribute access inside special methods +check-protected-access-in-special-methods=no + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp, + __post_init__ + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=cls + + +[DESIGN] + +# List of qualified class names to ignore when counting class parents (see +# R0901) +ignored-parents= + +# Maximum number of arguments for function / method. +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in an if statement (see R0916). +max-bool-expr=5 + +# Maximum number of branch for function / method body. +max-branches=12 + +# Maximum number of locals for function / method body. +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body. +max-returns=6 + +# Maximum number of statements in function / method body. +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "BaseException, Exception". +overgeneral-exceptions=BaseException, + Exception diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 000000000..0871881b0 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,44 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +# .readthedocs.yml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: doc/source/conf.py + +# Optionally set the version of Python and requirements required to build your docs +python: + version: 3.8 + install: + - requirements: requirements.txt + - requirements: doc/requirements.txt + - method: pip + path: . + - method: pip + path: . + +build: + image: latest diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..9706c62a4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,975 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.19.0] - 2022-01-25 + +### Changed + +- Covalent Beta Release + +## [0.18.9] - 2022-01-24 + +### Fixed + +- iframe in the docs landing page is now responsive + +## [0.18.8] - 2022-01-24 + +### Changed + +- Temporarily removed output tab +- Truncated dispatch id to fit left sidebar, add tooltip to show full id + +## [0.18.7] - 2022-01-24 + +### Changed + +- Many stylistic improvements to documentation, README, and CONTRIBUTING. + +## [0.18.6] - 2022-01-24 + +### Added + +- Test added to check whether an already decorated function works as expected with Covalent. +- `pennylane` package added to the `requirements-dev.txt` file. + +### Changed + +- Now using `inspect.signature` instead of `function.__code__` to get the names of function's parameters. + +## [0.18.5] - 2022-01-21 + +### Fixed + +- Various CI fixes, including rolling back regression in version validation, caching on s3 hosted badges, applying releases and tags correctly. + +## [0.18.4] - 2022-01-21 + +### Changed + +- Removed comments and unused functions in covalent_dispatcher +- `result_class.py` renamed to `result.py` + +### Fixed + +- Version was not being properly imported inside `covalent/__init__.py` +- `dispatch_sync` was not previously using the `results_dir` metadata field + +### Removed + +- Credentials in config +- `generate_random_filename_in_cache` +- `is_any_atom` +- `to_json` +- `show_subgraph` option in `draw` +- `calculate_node` + +## [0.18.3] - 2022-01-20 + +### Fixed + +- The gunicorn servers now restart more gracefully + +## [0.18.2] - 2022-01-21 + +### Changed + +- `tempdir` metadata field removed and replaced with `executor.local.cache_dir` + +## [0.18.1] - 2022-01-11 + +## Added + +- Concepts page + +## [0.18.0] - 2022-01-20 + +### Added + +- `Result.CANCELLED` status to represent the status of a cancelled dispatch. +- Condition to cancel the whole dispatch if any of the nodes are cancelled. +- `cancel_workflow` function which uses a shared variable provided by Dask (`dask.distributed.Variable`) in a dask client to inform nodes to stop execution. +- Cancel function for dispatcher server API which will allow the server to terminate the dispatch. +- How to notebook for cancelling a dispatched job. +- Test to verify whether cancellation of dispatched jobs is working as expected. +- `cancel` function is available as `covalent.cancel`. + +### Changed + +- In file `covalent/_shared_files/config.py` instead of using a variable to store and then return the config data, now directly returning the configuration. +- Using `fire_and_forget` to dispatch a job instead of a dictionary of Dask's `Future` objects so that we won't have to manage the lifecycle of those futures. +- The `test_run_dispatcher` test was changed to reflect that the dispatcher no longer uses a dictionary of future objects as it was not being utilized anywhere. + +### Removed + +- `with dask_client` context was removed as the client created in `covalent_dispatcher/_core/__init__.py` is already being used even without the context. Furthermore, it creates issues when that context is exited which is unnecessary at the first place hence not needed to be resolved. + +## [0.17.5] - 2022-01-19 + +### Changed + +- Results directory uses a relative path by default and can be overridden by the environment variable `COVALENT_RESULTS_DIR`. + +## [0.17.4] - 2022-01-19 + +### Changed + +- Executor parameters use defaults specified in config TOML +- If relative paths are supplied for stdout and stderr, those files are created inside the results directory + +## [0.17.3] - 2022-01-18 + +### Added + +- Sync function +- Covalent CLI tool can restart in developer mode + +### Fixed + +- Updated the UI address referenced in the README + +## [0.17.2] - 2022-01-12 + +### Added + +- Quantum gravity tutorial + +### Changed + +- Moved VERSION file to top level + +## [0.17.1] - 2022-01-19 + +### Added + +- `error` attribute was added to the results object to show which node failed and the reason behind it. +- `stdout` and `stderr` attributes were added to a node's result to store any stdout and stderr printing done inside an electron/node. +- Test to verify whether `stdout` and `stderr` are being stored in the result object. + +### Changed + +- Redesign of how `redirect_stdout` and `redirect_stderr` contexts in executor now work to allow storing their respective outputs. +- Executors now also return `stdout` and `stderr` strings, along with the execution output, so that they can be stored in their result object. + +## [0.17.0] - 2022-01-18 + +### Added + +- Added an attribute `__code__` to electron and lattice which is a copy of their respective function's `__code__` attribute. +- Positional arguments, `args`, are now merged with keyword arguments, `kwargs`, as close as possible to where they are passed. This was done to make sure we support both with minimal changes and without losing the name of variables passed. +- Tests to ensure usage of positional arguments works as intended. + +### Changed + +- Slight rework to how any print statements in lattice are sent to null. +- Changed `test_dispatcher_functional` in `basic_dispatcher_test.py` to account for the support of `args` and removed a an unnecessary `print` statement. + +### Removed + +- Removed `args` from electron's `init` as it wasn't being used anywhere. + +## [0.16.1] - 2022-01-18 + +### Changed + +- Requirement changed from `dask[complete]` to `dask[distributed]`. + +## [0.16.0] - 2022-01-14 + +### Added + +- New UI static demo build +- New UI toolbar functions - orientation, toggle params, minimap +- Sortable and searchable lattice name row + +### Changed + +- Numerous UI style tweaks, mostly around dispatches table states + +### Fixed + +- Node sidebar info now updates correctly + +## [0.15.11] - 2022-01-18 + +### Removed + +- Unused numpy requirement. Note that numpy is still being installed indirectly as other packages in the requirements rely on it. + +## [0.15.10] - 2022-01-16 + +## Added + +- How-to guide for Covalent dispatcher CLI. + +## [0.15.9] - 2022-01-18 + +### Changed + +- Switched from using human readable ids to using UUIDs + +### Removed + +- `human-id` package was removed along with its mention in `requirements.txt` and `meta.yaml` + +## [0.15.8] - 2022-01-17 + +### Removed + +- Code breaking text from CLI api documentation. +- Unwanted covalent_dispatcher rst file. + +### Changed + +- Installation of entire covalent_dispatcher instead of covalent_dispatcher/_service in setup.py. + +## [0.15.7] - 2022-01-13 + +### Fixed + +- Functions with multi-line or really long decorators are properly serialized in dispatch_source.py. +- Multi-line Covalent output is properly commented out in dispatch_source.py. + +## [0.15.6] - 2022-01-11 + +### Fixed + +- Sub-lattice functions are successfully serialized in the utils.py get_serialized_function_str. + +### Added + +- Function to scan utilized source files and return a set of imported modules (utils.get_imports_from_source) + +## [0.15.5] - 2022-01-12 + +### Changed + +- UI runs on port 47007 and the dispatcher runs on port 48008. This is so that when the servers are later merged, users continue using port 47007 in the browser. +- Small modifications to the documentation +- Small fix to the README + +### Removed + +- Removed a directory `generated` which was improperly added +- Dispatcher web interface +- sqlalchemy requirement + +## [0.15.4] - 2022-01-11 + +### Changed + +- In file `covalent/executor/base.py`, `pickle` was changed to `cloudpickle` because of its universal pickling ability. + +### Added + +- In docstring of `BaseExecutor`, a note was added specifying that `covalent` with its dependencies is assumed to be installed in the conda environments. +- Above note was also added to the conda env selector how-to. + +## [0.15.3] - 2022-01-11 + +### Changed + +- Replaced the generic `RuntimeError` telling users to check if there is an object manipulation taking place inside the lattice to a simple warning. This makes the original error more visible. + +## [0.15.2] - 2022-01-11 + +### Added + +- If condition added for handling the case where `__getattr__` of an electron is accessed to detect magic functions. + +### Changed + +- `ActiveLatticeManager` now subclasses from `threading.local` to make it thread-safe. +- `ValueError` in the lattice manager's `claim` function now also shows the name of the lattice that is currently claimed. +- Changed docstring of `ActiveLatticeManager` to note that now it is thread-safe. +- Sublattice dispatching now no longer deletes the result object file and is dispatched normally instead of in a serverless manner. +- `simulate_nitrogen_and_copper_slab_interaction.ipynb` notebook tutorial now does normal dispatching as well instead of serverless dispatching. Also, now 7 datapoints will be shown instead of 10 earlier. + +## [0.15.1] - 2022-01-11 + +### Fixed + +- Passing AWS credentials to reusable workflows as a secret + +## [0.15.0] - 2022-01-10 + +### Added + +- Action to push development image to ECR + +### Changed + +- Made the publish action reusable and callable + +## [0.14.1] - 2022-01-02 + +### Changed + +- Updated the README +- Updated classifiers in the setup.py file +- Massaged some RTD pages + +## [0.14.0] - 2022-01-07 + +### Added + +- Action to push static UI to S3 + +## [0.13.2] - 2022-01-07 + +### Changed + +- Completed new UI design work + +## [0.13.1] - 2022-01-02 + +### Added + +- Added eventlet requirement + +### Changed + +- The CLI tool can now manage the UI flask server as well +- [Breaking] The CLI option `-t` has been changed to `-d`, which starts the servers in developer mode and exposes unit tests to the server. + +## [0.13.0] - 2022-01-01 + +### Added + +- Config manager in `covalent/_shared_files/config.py` +- Default location for the main config file can be overridden using the environment variable `COVALENT_CONFIG_DIR` +- Ability to set and get configuration using `get_config` and `set_config` + +### Changed + +- The flask servers now reference the config file +- Defaults reference the config file + +### Fixed + +- `ValueError` caught when running `covalent stop` +- One of the functional tests was using a malformed path + +### Deprecated + +- The `electron.to_json` function +- The `generate_random_filename_in_cache` function + +### Removed + +- The `get_api_token` function + +## [0.12.13] - 2022-01-04 + +## Removed + +- Tutorial section headings + +## Fixed + +- Plot background white color + +## [0.12.12] - 2022-01-06 + +### Fixed + +- Having a print statement inside electron and lattice code no longer causes the workflow to fail. + +## [0.12.11] - 2022-01-04 + +### Added + +- Completed UI feature set for first release + +### Changed + +- UI server result serialization improvements +- UI result update webhook no longer fails on request exceptions, logs warning intead + +## [0.12.10] - 2021-12-17 + +### Added + +- Astrophysics tutorial + +## [0.12.9] - 2022-01-04 + +### Added + +- Added `get_all_node_results` method in `result_class.py` to return result of all node executions. + +- Added `test_parallelilization` test to verify whether the execution is now being achieved in parallel. + +### Changed + +- Removed `LocalCluster` cluster creation usage to a simple `Client` one from Dask. + +- Removed unnecessary `to_run` function as we no longer needed to run execution through an asyncio loop. + +- Removed `async` from function definition of previously asynchronous functions, `_run_task`, `_run_planned_workflow`, `_plan_workflow`, and `_run_workflow`. + +- Removed `uvloop` from requirements. + +- Renamed `test_get_results` to `test_get_result`. + +- Reran the how to notebooks where execution time was mentioned. + +- Changed how `dispatch_info` context manager was working to account for multiple nodes accessing it at the same time. + +## [0.12.8] - 2022-01-02 + +### Changed + +- Changed the software license to GNU Affero 3.0 + +### Removed + +- `covalent-ui` directory + +## [0.12.7] - 2021-12-29 + +### Fixed + +- Gunicorn logging now uses the `capture-output` flag instead of redirecting stdout and stderr + +## [0.12.6] - 2021-12-23 + +### Changed + +- Cleaned up the requirements and moved developer requirements to a separate file inside `tests` + +## [0.12.5] - 2021-12-16 + +### Added + +- Conda build CI job + +## [0.12.4] - 2021-12-23 + +### Changed + +- Gunicorn server now checks for port availability before starting + +### Fixed + +- The `covalent start` function now prints the correct port if the server is already running. + +## [0.12.3] - 2021-12-14 + +### Added + +- Covalent tutorial comparing quantum support vector machines with support vector machine algorithms implemented in qiskit and scikit-learn. + +## [0.12.2] - 2021-12-16 + +### Fixed + +- Now using `--daemon` in gunicorn to start the server, which was the original intention. + +## [0.12.1] - 2021-12-16 + +### Fixed + +- Removed finance references from docs +- Fixed some other small errors + +### Removed + +- Removed one of the failing how-to tests from the functional test suite + +## [0.12.0] - 2021-12-16 + +### Added + +- Web UI prototype + +## [0.11.1] - 2021-12-14 + +### Added + +- CLI command `covalent status` shows port information + +### Fixed + +- gunicorn management improved + +## [0.11.0] - 2021-12-14 + +### Added + +- Slack notifications for test status + +## [0.10.4] - 2021-12-15 + +### Fixed + +- Specifying a non-default results directory in a sub-lattice no longer causes a failure in lattice execution. + +## [0.10.3] - 2021-12-14 + +### Added + +- Functional tests for how-to's in documentation + +### Changed + +- Moved example script to a functional test in the pipeline +- Added a test flag to the CLI tool + +## [0.10.2] - 2021-12-14 + +### Fixed + +- Check that only `kwargs` without any default values in the workflow definition need to be passed in `lattice.draw(ax=ax, **kwargs)`. + +### Added + +- Function to check whether all the parameters without default values for a callable function has been passed added to shared utils. + +## [0.10.1] - 2021-12-13 + +### Fixed + +- Content and style fixes for getting started doc. + +## [0.10.0] - 2021-12-12 + +### Changed + +- Remove all imports from the `covalent` to the `covalent_dispatcher`, except for `_dispatch_serverless` +- Moved CLI into `covalent_dispatcher` +- Moved executors to `covalent` directory + +## [0.9.1] - 2021-12-13 + +### Fixed + +- Updated CONTRIBUTING to clarify docstring style. +- Fixed docstrings for `calculate_node` and `check_constraint_specific_sum`. + +## [0.9.0] - 2021-12-10 + +### Added + +- `prefix_separator` for separating non-executable node types from executable ones. + +- `subscript_prefix`, `generator_prefix`, `sublattice_prefix`, `attr_prefix` for prefixes of subscripts, generators, + sublattices, and attributes, when called on an electron and added to the transport graph. + +- `exclude_from_postprocess` list of prefixes to denote those nodes which won't be used in post processing the workflow. + +- `__int__()`, `__float__()`, `__complex__()` for converting a node to an integer, float, or complex to a value of 0 then handling those types in post processing. + +- `__iter__()` generator added to Electron for supporting multiple return values from an electron execution. + +- `__getattr__()` added to Electron for supporting attribute access on the node output. + +- `__getitem__()` added to Electron for supporting subscripting on the node output. + +- `electron_outputs` added as an attribute to lattice. + +### Changed + +- `electron_list_prefix`, `electron_dict_prefix`, `parameter_prefix` modified to reflect new way to assign prefixes to nodes. + +- In `build_graph` instead of ignoring all exceptions, now the exception is shown alongwith the runtime error notifying that object manipulation should be avoided inside a lattice. + +- `node_id` changed to `self.node_id` in Electron's `__call__()`. + +- `parameter` type electrons now have the default metadata instead of empty dictionary. + +- Instead of deserializing and checking whether a sublattice is there, now a `sublattice_prefix` is used to denote when a node is a sublattice. + +- In `dispatcher_stack_test`, `test_dispatcher_flow` updated to indicate the new use of `parameter_prefix`. + +### Fixed + +- When an execution fails due to something happening in `run_workflow`, then result object's status is now failed and the object is saved alongwith throwing the appropriate exception. + +## [0.8.5] - 2021-12-10 + +### Added + +- Added tests for choosing specific executors inside electron initialization. +- Added test for choosing specific Conda environments inside electron initialization. + +## [0.8.4] - 2021-12-10 + +### Changed + +- Removed _shared_files directory and contents from covalent_dispatcher. Logging in covalent_dispatcher now uses the logger in covalent/_shared_files/logging.py. + +## [0.8.3] - 2021-12-10 + +### Fixed + +- Decorator symbols were added to the pseudo-code in the quantum chemistry tutorial. + +## [0.8.2] - 2021-12-06 + +### Added + +- Quantum chemistry tutorial. + +## [0.8.1] - 2021-12-08 + +### Added + +- Docstrings with typehints for covalent dispatcher functions added. + +### Changed + +- Replaced `node` to `node_id` in `electron.py`. + +- Removed unnecessary `enumerate` in `covalent_dispatcher/_core/__init__.py`. + +- Removed `get_node_device_mapping` function from `covalent_dispatcher/_core/__init__.py` + and moved the definition to directly add the mapping to `workflow_schedule`. + +- Replaced iterable length comparison for `executor_specific_exec_cmds` from `if len(executor_specific_exec_cmds) > 0` + to `if executor_specific_exec_cmds`. + +## [0.8.0] - 2021-12-03 + +### Added + +- Executors can now accept the name of a Conda environment. If that environment exists, the operations of any electron using that executor are performed in that Conda environment. + +## [0.7.6] - 2021-12-02 + +### Changed + +- How to estimate lattice execution time has been renamed to How to query lattice execution time. +- Change result querying syntax in how-to guides from `lattice.get_result` to + `covalent.get_result`. +- Choose random port for Dask dashboard address by setting `dashboard_address` to ':0' in + `LocalCluster`. + +## [0.7.5] - 2021-12-02 + +### Fixed + +- "Default" executor plugins are included as part of the package upon install. + +## [0.7.4] - 2021-12-02 + +### Fixed + +- Upgraded dask to 2021.10.0 based on a vulnerability report + +## [0.7.3] - 2021-12-02 + +### Added + +- Transportable object tests +- Transport graph tests + +### Changed + +- Variable name node_num to node_id +- Variable name node_idx to node_id + +### Fixed + +- Transport graph `get_dependencies()` method return type was changed from Dict to List + +## [0.7.2] - 2021-12-01 + +### Fixed + +- Date handling in changelog validation + +### Removed + +- GitLab CI YAML + +## [0.7.1] - 2021-12-02 + +### Added + +- A new parameter to a node's result called `sublattice_result` is added. + This will be of a `Result` type and will contain the result of that sublattice's + execution. If a normal electron is executed, this will be `None`. + +- In `_delete_result` function in `results_manager.py`, an empty results directory + will now be deleted. + +- Name of a sublattice node will also contain `(sublattice)`. + +- Added `_dispatch_sync_serverless` which synchronously dispatches without a server + and waits for a result to be returned. This is the method used to dispatch a sublattice. + +- Test for sublatticing is added. + +- How-to guide added for sublatticing explaining the new features. + +### Changed + +- Partially changed `draw` function in `lattice.py` to also draw the subgraph + of the sublattice when drawing the main graph of the lattice. The change is + incomplete as we intend to add this feature later. + +- Instead of returning `plt`, `draw` now returns the `ax` object. + +- `__call__` function in `lattice.py` now runs the lattice's function normally + instead of dispatching it. + +- `_run_task` function now checks whether current node is a sublattice and acts + accordingly. + +### Fixed + +- Unnecessary lines to rename the node's name in `covalent_dispatcher/_core/__init__.py` are removed. + +- `test_electron_takes_nested_iterables` test was being ignored due to a spelling mistake. Fixed and + modified to follow the new pattern. + +## [0.7.0] - 2021-12-01 + +### Added + +- Electrons can now accept an executor object using the "backend" keyword argument. "backend" can still take a string naming the executor module. +- Electrons and lattices no longer have Slurm metadata associated with the executor, as that information should be contained in the executor object being used as an input argument. +- The "backend" keyword can still be a string specifying the executor module, but only if the executor doesn't need any metadata. +- Executor plugin classes are now directly available to covalent, eg: covalent.executor.LocalExecutor(). + +## [0.6.7] - 2021-12-01 + +### Added + +- Docstrings without examples for all the functions in core covalent. +- Typehints in those functions as well. +- Used `typing.TYPE_CHECKING` to prevent cyclic imports when writing typehints. + +### Changed + +- `convert_to_lattice_function` renamed to `convert_to_lattice_function_call`. +- Context managers now raise a `ValueError` instead of a generic `Exception`. + +## [0.6.6] - 2021-11-30 + +### Fixed + +- Fixed the version used in the documentation +- Fixed the badge URLs to prevent caching + +## [0.6.5] - 2021-11-30 + +### Fixed + +- Broken how-to links + +### Removed + +- Redundant lines from .gitignore +- *.ipynb from .gitignore + +## [0.6.4] - 2021-11-30 + +### Added + +- How-to guides for workflow orchestration. + - How to construct an electron + - How to construct a lattice + - How to add an electron to lattice + - How to visualize the lattice + - How to add constraints to lattices +- How-to guides for workflow and subtask execution. + - How to execute individual electrons + - How to execute a lattice + - How to execute multiple lattices +- How-to guides for status querying. + - How to query electron execution status + - How to query lattice execution status + - How to query lattice execution time +- How-to guides for results collection + - How to query electron execution results + - How to query lattice execution results + - How to query multiple lattice execution results +- Str method for the results object. + +### Fixed + +- Saving the electron execution status when the subtask is running. + +## [0.6.3] - 2021-11-29 + +### Removed + +- JWT token requirement. +- Covalent dispatcher login requirement. +- Update covalent login reference in README.md. +- Changed the default dispatcher server port from 5000 to 47007. + +## [0.6.2] - 2021-11-28 + +### Added + +- Github action for tests and coverage +- Badges for tests and coverage +- If tests pass then develop is pushed to master +- Add release action which tags and creates a release for minor version upgrades +- Add badges action which runs linter, and upload badges for version, linter score, and platform +- Add publish action (and badge) which builds a Docker image and uploads it to the AWS ECR + +## [0.6.1] - 2021-11-27 + +### Added + +- Github action which checks version increment and changelog entry + +## [0.6.0] - 2021-11-26 + +### Added + +- New Covalent RTD theme +- sphinx extension sphinx-click for CLI RTD +- Sections in RTD +- init.py in both covalent-dispatcher logger module and cli module for it to be importable in sphinx + +### Changed + +- docutils version that was conflicting with sphinx + +### Removed + +- Old aq-theme + +## [0.5.1] - 2021-11-25 + +### Added + +- Integration tests combining both covalent and covalent-dispatcher modules to test that + lattice workflow are properly planned and executed. +- Integration tests for the covalent-dispatcher init module. +- pytest-asyncio added to requirements. + +## [0.5.0] - 2021-11-23 + +### Added + +- Results manager file to get results from a file, delete a result, and redispatch a result object. +- Results can also be awaited to only return a result if it has either been completed or failed. +- Results class which is used to store the results with all the information needed to be used again along with saving the results to a file functionality. +- A result object will be a mercurial object which will be updated by the dispatcher and saved to a file throughout the dispatching and execution parts. +- Direct manipulation of the transport graph inside a result object takes place. +- Utility to convert a function definition string to a function and vice-versa. +- Status class to denote the status of a result object and of each node execution in the transport graph. +- Start and end times are now also stored for each node execution as well as for the whole dispatch. +- Logging of `stdout` and `stderr` can be done by passing in the `log_stdout`, `log_stderr` named metadata respectively while dispatching. +- In order to get the result of a certain dispatch, the `dispatch_id`, the `results_dir`, and the `wait` parameter can be passed in. If everything is default, then only the dispatch id is required, waiting will not be done, and the result directory will be in the current working directory with folder name as `results/` inside which every new dispatch will have a new folder named according to their respective dispatch ids, containing: + - `result.pkl` - (Cloud)pickled result object. + - `result_info.yaml` - yaml file with high level information about the result and its execution. + - `dispatch_source.py` - python file generated, containing the original function definitions of lattice and electrons which can be used to dispatch again. + +### Changed + +- `logfile` named metadata is now `slurm_logfile`. +- Instead of using `jsonpickle`, `cloudpickle` is being used everywhere to maintain consistency. +- `to_json` function uses `json` instead of `jsonpickle` now in electron and lattice definitions. +- `post_processing` moved to the dispatcher, so the dispatcher will now store a finished execution result in the results folder as specified by the user with no requirement of post processing it from the client/user side. +- `run_task` function in dispatcher modified to check if a node has completed execution and return it if it has, else continue its execution. This also takes care of cases if the server has been closed mid execution, then it can be started again from the last saved state, and the user won't have to wait for the whole execution. +- Instead of passing in the transport graph and dispatch id everywhere, the result object is being passed around, except for the `asyncio` part where the dispatch id and results directory is being passed which afterwards lets the core dispatcher know where to get the result object from and operate on it. +- Getting result of parent node executions of the graph, is now being done using the result object's graph. Storing of each execution's result is also done there. +- Tests updated to reflect the changes made. They are also being run in a serverless manner. + +### Removed + +- `LatticeResult` class removed. +- `jsonpickle` requirement removed. +- `WorkflowExecutionResult`, `TaskExecutionResult`, and `ExecutionError` singleton classes removed. + +### Fixed + +- Commented out the `jwt_required()` part in `covalent-dispatcher/_service/app.py`, may be removed in later iterations. +- Dispatcher server will now return the error message in the response of getting result if it fails instead of sending every result ever as a response. + +## [0.4.3] - 2021-11-23 + +### Added + +- Added a note in Known Issues regarding port conflict warning. + +## [0.4.2] - 2021-11-24 + +### Added + +- Added badges to README.md + +## [0.4.1] - 2021-11-23 + +### Changed + +- Removed old coverage badge and fixed the badge URL + +## [0.4.0] - 2021-11-23 + +### Added + +- Codecov integrations and badge + +### Fixed + +- Detached pipelines no longer created + +## [0.3.0] - 2021-11-23 + +### Added + +- Wrote a Code of Conduct based on +- Added installation and environment setup details in CONTRIBUTING +- Added Known Issues section to README + +## [0.2.0] - 2021-11-22 + +### Changed + +- Removed non-open-source executors from Covalent. The local SLURM executor is now +- a separate repo. Executors are now plugins. + +## [0.1.0] - 2021-11-19 + +### Added + +- Pythonic CLI tool. Install the package and run `covalent --help` for a usage description. +- Login and logout functionality. +- Executor registration/deregistration skeleton code. +- Dispatcher service start, stop, status, and restart. + +### Changed + +- JWT token is stored to file instead of in an environment variable. +- The Dask client attempts to connect to an existing server. + +### Removed + +- Removed the Bash CLI tool. + +### Fixed + +- Version assignment in the covalent init file. + +## [0.0.3] - 2021-11-17 + +### Fixed + +- Fixed the Dockerfile so that it runs the dispatcher server from the covalent repo. + +## [0.0.2] - 2021-11-15 + +### Changed + +- Single line change in ci script so that it doesn't exit after validating the version. +- Using `rules` in `pytest` so that the behavior in test stage is consistent. + +## [0.0.1] - 2021-11-15 + +### Added + +- CHANGELOG.md to track changes (this file). +- Semantic versioning in VERSION. +- CI pipeline job to enforce versioning. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..a39fdd91a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,428 @@ +First Steps +=========== + +To get started contributing to Covalent, you should fork this repository for your own development. (Learn more about [how to fork a repo](https://docs.github.com/en/get-started/quickstart/fork-a-repo).) + +Clone your fork locally: + +```shell +git clone https://github.com/my-github/covalent +``` + +where `my-github` is your personal GitHub account. + +We recommend using [Conda](https://www.anaconda.com/) to create an environment to install and develop Covalent. After you have [installed](https://docs.anaconda.com/anaconda/install/index.html) `conda`, create an environment: + +```shell +conda create -n covalent-dev python:3.8 +conda activate covalent-dev +``` + +Install Covalent's core requirements as well as the developer requirements: +```shell +conda install setuptools pip +pip install -e . +pip install -r tests/requirements.txt +pre-commit install +``` + +Start the Covalent servers in developer mode: +```shell +covalent start -d +``` + +Finally, run the tests to verify your installation: +```shell +pytest -v +``` + + +Style Guide +=========== + +Contributing to the Covalent codebase should be an easy process, but there are a few things to consider to ensure your contributions meet the minimum software quality standards. The main points are explained below, and they are roughly grouped into the following categories: stylization, documentation, and testing. + +## General Guidelines +- Use American English spellings and grammar.  Documentation with typos will be rejected. +- Use complete sentences with capitalization and punctuation, except in short descriptions of arguments, return values, attributes, and exceptions in source code. +- Multi-sentence argument descriptions, or longer sentence fragments with mid-sentence punctuation marks, should use capitalization and punctuation. +- Comments may be written more informally than docstrings, as long as consistency and clarity are maintained. Capitalization and punctuation should be used with multi-sentence comments to aid with readability. +- Avoid complex stylization in docstrings; these must be readable for users in a terminal/Jupyter environment. +- Assume the user does not have access to any source files. +- Variables must be restricted to the scope in which they are used; avoid use of global variables except when absolutely necessary. +- Limit all lines to 99 characters.  Use a four-character indent for Python files; bash files use a two-character indent, and C uses a tab indent. These will be adjusted as needed by the pre-commit hooks. +- Input parameters to scripts should be passed using flags, rather than positional arguments. This may be implemented using the `getopt` libraries.  Bash scripts may accept parameters passed with or without flags. +- Functions should perform a single task.  Generally functions should not contain more than 30 lines of code, not including line breaks, comments, and whitespace. +- Use the `pylint` tool to improve the quality of your code. Contributions which decrease the codebase's code quality will be rejected. +- All changes must be documented in the [changelog](./CHANGELOG.md) as a new version. +- New features or changes to UX must include a usage description in the form of a [how-to guide](https://covalent.readthedocs.io/en/latest/how_to/index.html). +- All software source files should contain the copyright boilerplate displayed below, which includes a docstring describing the purpose of the file. + +## Source Code Boilerplate +All files submitted must contain the following before all other lines: + +```python +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Single-sentence description of the file.""" +``` + +Bash files may contain the shebang `#!/usr/bin/env bash` on a line before the boilerplate.  Afterwards, the following should be written before the body of code: + +```bash +set -eu -o pipefail +``` + +and files should end with an explicit exit code, e.g., `exit 0` indicates a successful exit. + +## Naming Conventions +- Class names use `CamelCase` +- Functions, variables, filenames, and directories use `snake_case` +- Constants use `SCREAMING_SNAKE_CASE` +- Acronyms are a sequence of all-capitalized letters +- Names should be descriptive and concise +- Mathematical variables (“x”) may be used only when they are documented. This may be appropriate for standard variables used in literature. +- Avoid using “I”, “l”, and “O” as variable names +- Private objects and methods/functions of a class should start with an underscore, e.g., `self._variable` or `self._internal_function()`. A "private" class object is one that should not be used outside of the class definition. Unlike C++, Python has no way of stopping a user/developer from accessing or modifying any object in the class (hence the quotations around private). The underscore lets them know the object is for internal use only and that its internal usage could change without warning. + +## References +- Add references to other code units where applicable. Use the roles :class:, :func:, :attr:, :meth:, and :mod: so that Sphinx generates a cross-reference in generated documentation. +- Add URL references to code taken from or inspired by code found online. +- All digital references must specify a DOI, ISBN, arXiv ID, or URL, in that order of preference. +- Add references to literature where applicable.  Academic journal articles should be in the following format: + +``` +A.B. Lastname1, C. Lastname2 and D. Lastname3. Title of Article. Jour. Abbrev. 1, 123456 (2021). +doi: 10.1001/abcdef +arXiv: quant-ph/000000 +``` + +Standard journal abbreviations can be found [here](https://www.library.caltech.edu/journal-title-abbreviations).  In the above example, ‘1’ refers to the volume number, and ‘123456’ refers to the first page number of the article.  For six or more authors use the first author’s name followed by *et al.*  References to other material should follow the *apsrev4-1* bibliography style and generally follow the same stylization as that for articles.  The DOI, if one exists, should be on the first line following a reference; if an arXiv ID also exists it may be added on a line following the DOI. + +## Python Docstrings + +Docstrings should follow [Google style](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings). + +### Functions and Methods + +```python +def func(arg1: , arg2: , arg3: = "default_value", **kwargs) -> : + """Single sentence that summarizes the function. + + Multi-line description of the function (optional, only if necessary). + + Args: + arg1: Description. + Continuation line is indented if needed. + arg2: Description. + arg3: Description. Do not provide the default. + value, as this is already present in the signature. + + Returns: + Description of the return type and semantics. + Continuation line is on the same indent level. + + Raises: + : description + + .. seealso:: :func:`~.relevant_func`, :class:`~.RelevantClass` (optional) + + Example: + Minimal example with 1 or 2 code blocks (required). + .. code-block:: python + + myvalue = func(arg1, arg2, arg3) + + + Usage Details: + More complicated use cases, options, and larger code blocks (optional). + + Related tutorials: + Links to any relevant notebook examples (optional). + + References: + References to academic articles, books, or websites (optional). + + A.B. Lastname1, C. Lastname2 and D. Lastname3. Title of Article. Jour. Abbrev. 1, 123456 (2021). + doi: 10.1001/abcdef + arXiv: quant-ph/000000 + """ +``` + +- Relevant mathematical expressions should be formatted using inline latex and placed in the multi-line description.  Important or long equations may go on their own line. +- Algorithmic functions should contain details about scaling with time and/or problem size, e.g., O(N); this information also goes in the multi-line description. +- ``, ``, `` and `` are placeholders for the type hints of `arg1`, `arg2`, `arg3` and the return value. + +### Classes + +```python +class MyClass: + """Single sentence that summarizes the class. + + Multi-line description of the class (optional, if required). + + Attributes: + attr1: description + """ +``` + +- Include public attributes here in the `Attributes` section, using the same formatting as a function's `Args` section. +- Do not list methods in the class docstring. +- Private attributes of a class do not need to be described in the class docstring. These are class objects that should not be used outside of the class definition. + +### Variables +Variables may optionally be documented using a docstring below their definition: + +```python +num_gates = {"CNOT": 17, "RY": 31} +"""dict[str, int]: Number of gates in wire 2""" +``` + +## Bash Docstrings + +All bash scripts must begin by validating input parameters and offering a help string: + +```bash +# This example uses two parameters: an integer and a string +if [ $# -eq 2 ] && [ $1 =~ '^[+-]?[0-9]+$' ] ; then + var1=$1 + var2=$2 +else + echo "$(basename $0) [var1] [var2] -- short description of this script." + echo "Longer help string and explanation of parameters." + exit 1 +fi + +# Continue with the rest of the script +``` + +## Code Examples + +- You may assume that ‘covalent’ is imported as ‘ct’. All other imports must be specified explicitly. +- For single line statements and associated output, use Python console syntax (pycon): + +```python +>>> pipeline.dispatch(**params) # Dispatching a workflow returns a unique dispatch id. +'8a7bfe54-d3c7-4ca1-861b-f55af6d5964a' +``` + +- Multi-line statements should use “...” to indicate continuation lines: + +```python +>>> dispatch_ids = [] +>>> params = [1, 2, 3, 4] +>>> for a in params: +... dispatch_ids.append(pipeline.dispatch(a=a)) +``` + +- For larger, more complicated code blocks, use standard Python code-block with Python console syntax for displaying output: + +```python +>>> @ct.electron +... def identity(x): +... return x +... +>>> @ct.lattice +... def pipeline(a): +... res = identity(a) +... return res +... +>>> dispatch_id = pipeline.dispatch(a=1) +>>> result = pipeline.get_result(dispatch_id=dispatch_id) +>>> print(result) + +Lattice Result +============== +status: COMPLETED +result: 1 +inputs: {'a': 1} +error: None + +start_time: 2022-01-24 04:13:00.667919+00:00 +end_time: 2022-01-24 04:13:00.684457+00:00 + +results_dir: /home/user/covalent +dispatch_id: e4efd26c-240d-4ab1-9826-26ada91e429f +``` + +## Code Comments + +- Comments are used to explain the implementation or algorithm.  Assume the reader is a proficient programmer and understands basic principles and syntax. +- Self-document code when possible.  Code should be clear and concise, flow logically, and be organized into stanzas according to what’s happening.  This helps avoid *unnecessary* comments. +- Comments should occur directly above the code that is being described.  Use a single space between the "#" character and the start of text. + +## Python Type Hints + +Type hints should be used for input parameters in functions and classes, as well as for return values as well. The typing module should be used for several circumstances: + +- When a parameter or return type is a container for multiple parameters. Examples include a dict mapping strings to floats uses, `Dict[str,float]`, or a list of integers uses, `List[int]` + +- Nested Types: A dict mapping an integer to a list of floats is written `Dict[int,List[float]]` + +- If a parameter can be multiple types, use `Union`. E.g., if it can be a string **or** a list of strings **or** an integer, use `Union[str,List[str],int]`. + +- If a parameter can be anything, use `Any`. This is more permissive than using `object`. Type checkers will ignore it completely. + +- Optional parameters use `Optional`. E.g., an optional integer is written `Optional[int]`. + +Any user-defined class type can be used in a type hint, but the class must have been imported beforehand. + +Some examples of type hints in use: + +```python +from typing import Union, List, Dict, Any, Optional + +import MyClass + +def some_function(some_variable: float, + some_index: int, + float_or_string: Union[float,str], + some_integer_list: List[int], + some_string_list: List[str], + my_class_object: MyClass, # This will fail if MyClass has not been imported + some_dict: Dict[int,str], + literally_anything: Any, + optional_string: Optional[str] = 'default string', + optional_int: Optional[int] = -1, + optional_int_or_string: Optional[Union[int,str]] = 9999 + optional_int_list: Optional[List[int]] = [0,1,2,3]) -> Union[str,float,None]: + + """Function description + + Args: + some_variable: some_variable description + some_index: some_index description + float_or_string: float_or_string description + some_integer_list: some_integer_list description + some_string_list: some_string_list description + my_class_object: my_class_object description + some_dict: some_dict description + literally_anything: literally_anything description + optional_string: optional_string description + optional_int: optional_int description + optional_int_or_string: optional_int_or_string description + optional_int_list: optional_int_list description + + Returns: + return_variable: return description + """ + + n = 5 * some_index + + if n == 20: + return 'ok' + elif n == 455: + return n * 3.14159 + else: + return +``` + +## Python Logging + +Covalent uses the Python logging module for errors, warnings, debug and info statements. There is a small module (`covalent/_shared_files/logger.py`) which encapsulates the default logger. Modules can access the logger using the following: + +```python +from covalent._shared_files import logger +app_log = logger.app_log +log_stack_info = logger.log_stack_info +log_debug_info = logger.log_debug_info +``` + +Warning, info and debug statements are done with the following commands: + +```python +>>> app_log.warning('here is the warning message') +: Line 8 in : +WARNING - here is the warning message +>>> app_log.info('message for informational purposes') +: Line 12 in : +INFO - message for informational purposes +>>> app_log.debug('debug statement') +: Line 15 in : +DEBUG - debug statement +``` + +where `` and `` are stand-ins for the file and function that the log statement occurred in. + +For more urgent messages, denoting errors which will stop the program from executing correctly, use error statements. Usage is similar, except that we want the program to exit and optionally show a stack-trace pointing to the error. + +The level of warning seen when executing code depends on the user's environment variable `LOGLEVEL`. Choices are: + + +|Level|Numeric value| +|-----|-------------| +|CRITICAL|50| +|ERROR|40| +|WARNING|30| +|INFO|20| +|DEBUG|10| +|NOTSET|0| + +The lower the level, the more log messages are shown to the user. Executing, for example, + +``` +export LOGLEVEL=INFO +``` + +guarantees all info, warning, error and critical messages will be shown. If this environment variable is not set, the default value of `WARNING` is used. + +## Writing Tests +All feature changes and bug fixes should be accompanied by tests. These can be a +combination of unit, integration and functional tests. Unit tests are the highest priority and +should be the bulk of the tests in the repo. Following that, integration tests, checking that +various modules function as expected are the next highest priority. Lastly, functional tests, +which test various software use cases should be proportionately the minority +of the tests (without undermining their importance). + +In the case of bug fixes, it is necessary to write tests for which the code breaks before +implementing the bug fix. + +It is further advisable to consider how feature changes could be implemented so that the code +is easily testable. + +`pytest` is the framework of choice for testing in this repo with additional packages such as +`pytest-asyncio` to test asynchronous code and `pytest-mock` for the purpose of mocking and +monkey-patching. + +The test suite for covalent can be run locally via: + +```buildoutcfg +pytest -v +``` + +Running the entire test suite will take a while and for the purpose of development, one can +focus on more specific tests using syntax in the examples shown below. + +1. To run a specific test module: +```buildoutcfg +pytest tests/covalent_dispatcher_tests/_executor/local_test.py -vv -s +``` + +2. To run a specific test: + +```buildoutcfg +pytest tests/electron_return_value_test.py::test_arithmetic_1_rev -vv -s +``` + +Contributor License Agreement +============================= + +All contributors to Covalent must agree to the terms in the [Contributor License Agreement](https://gist.github.com/wjcunningham7/3f21c684fc60c7598e0fe711caeb9ac1). Individual contributors should sign on their own behalf, while corporate contributors should sign on behalf of their employer. If you have any questions, direct them to the [support team](mailto:support@agnostiq.ai). diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..0e8d3758b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,29 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +FROM python:3.8-slim-buster + +RUN mkdir -p /opt/covalent +COPY . /opt/covalent +RUN pip install --no-cache-dir /opt/covalent + +EXPOSE 80 + +ENTRYPOINT gunicorn -w 1 -t 30 -b 0.0.0.0:80 --chdir /opt/covalent/covalent_dispatcher/_service app:app diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..be3f7b28e --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md index 802992c42..22dfefd2b 100644 --- a/README.md +++ b/README.md @@ -1 +1,205 @@ -Hello world +  + +
+ + + +  + +[![version](https://github-covalent-badges.s3.amazonaws.com/badges/version.svg?maxAge=3600)](https://github.com/AgnostiqHQ/covalent) +[![python](https://img.shields.io/badge/python-3.8-blue.svg)](https://www.python.org/downloads/release/python-380) +[![tests](https://github.com/AgnostiqHQ/covalent/actions/workflows/tests.yml/badge.svg)](https://github.com/AgnostiqHQ/covalent/actions) +[![publish](https://github.com/AgnostiqHQ/covalent/actions/workflows/publish.yml/badge.svg)](https://github.com/AgnostiqHQ/covalent/actions) +[![docs](https://readthedocs.org/projects/covalent/badge/?version=latest)](https://covalent.readthedocs.io/en/latest/?badge=latest) +[![codecov](https://codecov.io/gh/AgnostiqHQ/covalent/branch/master/graph/badge.svg?token=YGHCB3DE4P)](https://codecov.io/gh/AgnostiqHQ/covalent) +[![agpl](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0.en.html) + +
+ +## 🤔 What is Covalent? + +Covalent is a Pythonic workflow tool used to execute tasks on advanced computing hardware. Users can decorate their existing Python functions as electrons (tasks) or lattices (workflows) and then run these functions locally or dispatch them to various classical and quantum backends according to the hardware requirements. After submitting workflows, users can use the browser-based Covalent viewer to visualize dependencies and the workflow execution progress. User can view a variety of information about the workflow such as the status, errors, the workflow's dependency graph, and metadata, among other things. Covalent is designed to make it easy for users to keep track of their computationally heavy experiments by providing a simple and intuitive framework to store, modify, and re-analyze computational experiments. Covalent is rapidly expanding to include support for a variety of cloud interfaces, including HPC infrastructure tools developed by major cloud providers and emerging quantum APIs. It has never been easier to deploy your code on the world's most advanced computing hardware with Covalent. Read more in the official [documentation](https://covalent.readthedocs.io/en/latest/). + +## ✨ Features + +
+ + +With Covalent's UI, bring your workflows to life! +
+ +- **Purely Pythonic** : No need to learn any new syntax or mess around with YAML. Construct your complex workflow programmatically with native python functions. By just adding decorators to your functions, you can supercharge your experiments. +- **Native parallelization** : Covalent natively parallelizes parts of your workflow that are independent of each other. +- **Monitor with UI** : Covalent provides an intuitive and aesthetically beautiful browser-based user interface to monitor and manage your workflows. +- **Abstracted dataflow** : No need to worry about the details of the underlying data structures. Covalent automatically takes care of data dependencies in the background while you concentrate on understanding the big picture. +- **Result management** : Covalent automatically manages the results of your workflows. Whenever you need to modify parts of your workflow, from inputs to components, Covalent natively stores and saves the run of every experiment in a reproducible format. +- **Little-to-no overhead** : Covalent is designed to be as lightweight as possible and is optimized for the most common use cases. Covalent's overhead is less than 0.1% of the total runtime for typical high compute applications and often has a constant overhead of ~ 10-100μs -- and this is constantly being optimized. +- **Interactive** : Unlike other workflow tools, Covalent is interactive. You can view, modify, and re-submit workflows directly within a Jupyter notebook. + +For a more in-depth description of Covalent's features and how they work, refer to the [Concepts](https://covalent.readthedocs.io/en/latest/concepts/concepts.html) page. + +## 📦 Installation + +Covalent is developed using Python version 3.8 on Linux and macOS. The easiest way to install Covalent is using the PyPI package manager: + +```console +pip install cova +``` + +Refer to the [Getting Started](https://covalent.readthedocs.io/en/latest/getting_started/index.html) guide for more details on setting up. + +## 📖 Example + +Begin by starting the Covalent servers: + +```console +covalent start +``` + +Navigate to the user interface at `http://localhost:47007` to monitor workflow execution progress. + +In your Python code, it's as simple as adding a few decorators! Consider the following example which uses a support vector machine (SVM) to classify types of iris flowers. + + + + + + + + + + + + + + + +
Without CovalentWith Covalent
+ +``` python +from numpy.random import permutation +from sklearn import svm, datasets + +def load_data(): + iris = datasets.load_iris() + perm = permutation(iris.target.size) + iris.data = iris.data[perm] + iris.target = iris.target[perm] + return iris.data, iris.target + +def train_svm(data, C, gamma): + X, y = data + clf = svm.SVC(C=C, gamma=gamma) + clf.fit(X[90:], y[90:]) + return clf + +def score_svm(data, clf): + X_test, y_test = data + return clf.score( + X_test[:90], + y_test[:90] + ) + +def run_experiment(C=1.0, gamma=0.7): + data = load_data() + clf = train_svm( + data=data, + C=C, + gamma=gamma + ) + score = score_svm(data=data, clf=clf) + return score + +result=run_experiment(C=1.0, gamma=0.7) +``` + + + + +```python +from numpy.random import permutation +from sklearn import svm, datasets +import covalent as ct + +@ct.electron +def load_data(): + iris = datasets.load_iris() + perm = permutation(iris.target.size) + iris.data = iris.data[perm] + iris.target = iris.target[perm] + return iris.data, iris.target + +@ct.electron +def train_svm(data, C, gamma): + X, y = data + clf = svm.SVC(C=C, gamma=gamma) + clf.fit(X[90:], y[90:]) + return clf + +@ct.electron +def score_svm(data, clf): + X_test, y_test = data + return clf.score( + X_test[:90], + y_test[:90] + ) + +@ct.lattice +def run_experiment(C=1.0, gamma=0.7): + data = load_data() + clf = train_svm( + data=data, + C=C, + gamma=gamma + ) + score = score_svm( + data=data, + clf=clf + ) + return score + +dispatch_id = + run_experiment.dispatch( + C=1.0, + gamma=0.7 + ) +result = ct.get_result(dispatch_id) +``` +
+ +```python +>>> print(result) +0.988888888 +``` + + +```python +>>> print(f""" +... status = {result.status} +... input = {result.inputs} +... result = {result.result} +... """) +status = Status(STATUS='COMPLETED') +input = {'C': 1.0, 'gamma': 0.7} +result = 0.9666666666666667 +``` +
+ + +For more examples, please refer to the [Covalent tutorials](https://covalent.readthedocs.io/en/latest/tutorials/tutorials.html). + +## 📚 Documentation + +The official documentation includes tips on getting started, some high level concepts, a handful of tutorials, and the API documentation. To learn more, please refer to the [Covalent documentation](https://covalent.readthedocs.io/en/latest/). + +## ✔️ Contributing + +To contribute to Covalent, refer to the [Contribution Guidelines](./CONTRIBUTING.md). We use GitHub's [issue tracking](https://github.com/AgnostiqHQ/covalent/issues) to manage known issues, bugs, and pull requests. Get started by forking the develop branch and submitting a pull request with your contributions. Improvements to the documentation, including tutorials and how-to guides, are also welcome from the community. Participation in the Covalent community is governed by the [Code of Conduct](./CODE_OF_CONDUCT.md). + +## 📝 Release Notes + +Release notes are available in the [Changelog](./CHANGELOG.md). + +## 📃 License + +Covalent is licensed under the GNU Affero GPL 3.0 License. Covalent may be distributed under other licenses upon request. See the [LICENSE](LICENSE) file or contact the [support team](mailto:support@agnostiq.ai) for more details. diff --git a/VERSION b/VERSION new file mode 100644 index 000000000..1cf0537c3 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.19.0 diff --git a/covalent/VERSION b/covalent/VERSION new file mode 100644 index 000000000..2a0970ca7 --- /dev/null +++ b/covalent/VERSION @@ -0,0 +1 @@ +0.16.1 diff --git a/covalent/__init__.py b/covalent/__init__.py index e69de29bb..c68db1e2e 100644 --- a/covalent/__init__.py +++ b/covalent/__init__.py @@ -0,0 +1,42 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Main Covalent public functionality.""" + +import os + +from . import executor +from ._results_manager.results_manager import cancel, get_result, sync +from ._shared_files.config import get_config, reload_config, set_config +from ._shared_files.util_classes import RESULT_STATUS as status +from ._workflow import electron, lattice + +try: + with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../VERSION")) as f: + __version__ = f.read().strip() +except FileNotFoundError: + pass + +__all__ = [s for s in dir() if not s.startswith("_")] + +for _s in dir(): + if not _s.startswith("_"): + _obj = globals()[_s] + _obj.__module__ = __name__ diff --git a/covalent/_results_manager/__init__.py b/covalent/_results_manager/__init__.py new file mode 100644 index 000000000..8b525a5e0 --- /dev/null +++ b/covalent/_results_manager/__init__.py @@ -0,0 +1,23 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + + +from . import results_manager +from .result import Result diff --git a/covalent/_results_manager/result.py b/covalent/_results_manager/result.py new file mode 100644 index 000000000..e4d43427c --- /dev/null +++ b/covalent/_results_manager/result.py @@ -0,0 +1,478 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Result object.""" + +import os +from datetime import datetime +from pathlib import Path +from typing import TYPE_CHECKING, Any, Dict, List + +import cloudpickle as pickle +import yaml + +from .._shared_files.util_classes import RESULT_STATUS +from .utils import convert_to_lattice_function_call + +if TYPE_CHECKING: + from .._shared_files.util_classes import Status + from .._workflow.lattice import Lattice + + +class Result: + """ + Result class to store and perform operations on the result obtained from a dispatch. + + Attributes: + lattice: "Lattice" object which was dispatched. + results_dir: Directory where the result will be stored. + It'll be in the format of "//". + dispatch_id: Dispatch id assigned to this dispatch. + status: Status of the result. It'll be one of the following: + - Result.NEW_OBJ: When it is a new result object. + - Result.COMPLETED: When processing of all the nodes has completed successfully. + - Result.RUNNING: When some node executions are in process. + - Result.FAILED: When one or more node executions have failed. + - Result.CANCELLED: When the dispatch was cancelled. + result: Final result of the dispatch, i.e whatever the "Lattice" was returning as a function. + inputs: Inputs sent to the "Lattice" function for dispatching. + error: Error due to which the execution failed. + + Functions: + save_result: Save the result object to the passed results directory or to self.results_dir by default. + get_all_node_outputs: Return all the outputs of all the node executions. + """ + + NEW_OBJ = RESULT_STATUS.NEW_OBJECT + COMPLETED = RESULT_STATUS.COMPLETED + RUNNING = RESULT_STATUS.RUNNING + FAILED = RESULT_STATUS.FAILED + CANCELLED = RESULT_STATUS.CANCELLED + + def __init__(self, lattice: "Lattice", results_dir: str, dispatch_id: str = None) -> None: + + self._start_time = None + self._end_time = None + + self._results_dir = results_dir + + self._lattice = lattice + self._dispatch_id = dispatch_id + + self._status = Result.NEW_OBJ + + self._result = None + self._inputs = lattice.kwargs + + self._error = None + + def __str__(self): + show_result_str = f""" +Lattice Result +============== +status: {self._status} +result: {self.result} +inputs: {self.inputs} +error: {self.error} + +start_time: {self.start_time} +end_time: {self.end_time} + +results_dir: {self.results_dir} +dispatch_id: {self.dispatch_id} + +Node Outputs +------------ +""" + + node_outputs = self.get_all_node_outputs() + for k, v in node_outputs.items(): + show_result_str += f"{k}: {v}\n" + + return show_result_str + + @property + def start_time(self): + """ + Start time of processing the dispatch. + """ + + return self._start_time + + @property + def end_time(self): + """ + End time of processing the dispatch. + """ + + return self._end_time + + @property + def results_dir(self): + """ + Results directory used to save this result object. + """ + + return self._results_dir + + @property + def lattice(self): + """ + "Lattice" object which was dispatched. + """ + + return self._lattice + + @property + def dispatch_id(self): + """ + Dispatch id of current dispatch. + """ + + return self._dispatch_id + + @property + def status(self): + """ + Status of current dispatch. + """ + + return self._status + + @property + def result(self): + """ + Final result of current dispatch. + """ + + return self._result + + @property + def inputs(self): + """ + Inputs sent to the "Lattice" function for dispatching. + """ + + return self._inputs + + @property + def error(self): + """ + Error due to which the dispatch failed. + """ + + return self._error + + def _initialize_nodes(self) -> None: + """ + Initialize the nodes of the transport graph with a blank result. + This is called after `self.lattice.transport_graph` has been deserialized. + + Args: + None + + Returns: + None + """ + + self._num_nodes = self.lattice.transport_graph.get_internal_graph_copy().number_of_nodes() + for node_id in range(self._num_nodes): + self._update_node( + node_id, + "", + None, + None, + Result.NEW_OBJ, + None, + None, + None, + None, + ) + + def get_node_result(self, node_id: int) -> dict: + """Return the result of a particular node. + + Args: + node_id: The node id. + + Returns: + node_result: The result of the node containing below in a dictionary format: + - node_id: The node id. + - node_name: The name of the node. + - start_time: The start time of the node execution. + - end_time: The end time of the node execution. + - status: The status of the node execution. + - output: The output of the node unless error occured in which case None. + - error: The error of the node if occured else None. + - sublattice_result: The result of the sublattice if any. + - stdout: The stdout of the node execution. + - stderr: The stderr of the node execution. + """ + + return { + "node_id": node_id, + "node_name": self.lattice.transport_graph.get_node_value(node_id, "node_name"), + "start_time": self.lattice.transport_graph.get_node_value(node_id, "start_time"), + "end_time": self.lattice.transport_graph.get_node_value(node_id, "end_time"), + "status": self.lattice.transport_graph.get_node_value(node_id, "status"), + "output": self.lattice.transport_graph.get_node_value(node_id, "output"), + "error": self.lattice.transport_graph.get_node_value(node_id, "error"), + "sublattice_result": self.lattice.transport_graph.get_node_value( + node_id, "sublattice_result" + ), + "stdout": self.lattice.transport_graph.get_node_value(node_id, "stdout"), + "stderr": self.lattice.transport_graph.get_node_value(node_id, "stderr"), + } + + def get_all_node_outputs(self) -> dict: + """ + Return output of every node execution. + + Args: + None + + Returns: + node_outputs: A dictionary containing the output of every node execution. + """ + + return { + self._get_node_name(node_id): self._get_node_output(node_id) + for node_id in range(self._num_nodes) + } + + def get_all_node_results(self) -> List[Dict]: + """ + Get all the node results. + + Args: + None + + Returns: + node_results: A list of dictionaries containing the result of every node execution. + """ + + return [self.get_node_result(i) for i in range(self._num_nodes)] + + def _get_node_name(self, node_id: int) -> str: + """ + Returns the name of the node with given node id. + + Args: + node_id: The node id. + + Returns: + node_name: The name of said node. + """ + + return self.lattice.transport_graph.get_node_value(node_id, "node_name") + + def _get_node_status(self, node_id: int) -> "Status": + """ + Returns the status of a node. + + Args: + node_id: The node id. + + Returns: + status: The status of said node. + """ + + return self.lattice.transport_graph.get_node_value(node_id, "status") + + def _get_node_output(self, node_id: int) -> Any: + """ + Return the output of a node. + + Args: + node_id: The node id. + + Returns: + output: The output of said node. + Will return None if error occured in execution. + """ + + return self.lattice.transport_graph.get_node_value(node_id, "output") + + def _get_node_error(self, node_id: int) -> Any: + """ + Return the error of a node. + + Args: + node_id: The node id. + + Returns: + error: The error of said node. + Will return None if no error occured in execution. + """ + + return self.lattice.transport_graph.get_node_value(node_id, "error") + + def _update_node( + self, + node_id: int, + node_name: str, + start_time: "datetime", + end_time: "datetime", + status: "Status", + output: Any, + error: Exception, + sublattice_result: "Result" = None, + stdout: str = None, + stderr: str = None, + ) -> None: + """ + Update the node result in the transport graph. + Called after any change in node's execution state. + + Args: + node_id: The node id. + node_name: The name of the node. + start_time: The start time of the node execution. + end_time: The end time of the node execution. + status: The status of the node execution. + output: The output of the node unless error occured in which case None. + error: The error of the node if occured else None. + sublattice_result: The result of the sublattice if any. + stdout: The stdout of the node execution. + stderr: The stderr of the node execution. + + Returns: + None + """ + + self._lattice.transport_graph.set_node_value(node_id, "node_name", node_name) + self._lattice.transport_graph.set_node_value(node_id, "start_time", start_time) + self._lattice.transport_graph.set_node_value(node_id, "end_time", end_time) + self._lattice.transport_graph.set_node_value(node_id, "status", status) + self._lattice.transport_graph.set_node_value(node_id, "output", output) + self._lattice.transport_graph.set_node_value(node_id, "error", error) + self._lattice.transport_graph.set_node_value( + node_id, "sublattice_result", sublattice_result + ) + self._lattice.transport_graph.set_node_value(node_id, "stdout", stdout) + self._lattice.transport_graph.set_node_value(node_id, "stderr", stderr) + + def save(self, directory: str = None) -> None: + """ + Save the result object to a file. + + Args: + directory: The directory to save the result object to. + If not specified, the result object will be saved to the + `self.results_dir` directory. + + Returns: + None + """ + + directory = directory or self.results_dir + + result_folder_path = os.path.join(directory, f"{self.dispatch_id}") + Path(result_folder_path).mkdir(parents=True, exist_ok=True) + + result_info = { + "dispatch_id": self.dispatch_id, + "result_status": self.status, + "start_time": self.start_time.strftime("%Y-%m-%d %H:%M") + if self.start_time + else self.start_time, + "end_time": self.end_time.strftime("%Y-%m-%d %H:%M") + if self.end_time + else self.end_time, + } + + with open(os.path.join(result_folder_path, "result.pkl"), "wb") as f: + f.write(pickle.dumps(self)) + + with open(os.path.join(result_folder_path, "result_info.yaml"), "w") as f: + yaml.dump(result_info, f) + + self._write_dispatch_to_python_file() + + def _convert_to_electron_result(self) -> Any: + """ + Convert the result object to an electron's result. + + Args: + None + + Returns: + result: The final output of the dispatch. + """ + + return self.result + + def _write_dispatch_to_python_file(self, directory: str = None) -> None: + """ + Writes the source code of user function definitions to a python file. + + Args: + directory: The directory to write the source file to. + + Returns: + None + """ + + directory = directory or self.results_dir + + import pkg_resources + + dispatch_function = ( + f"# File created by Covalent using covalent version {pkg_resources.get_distribution('cova').version}\n" + f"# Note that this file does not contain any global imports you did in your original dispatch\n" + f"# Covalent result -" + ) + result_string_lines = str(self.result).split("\n") + if len(result_string_lines) == 1: + dispatch_function += f" {self.result}\n\n" + else: + dispatch_function += "\n" + for line in result_string_lines: + dispatch_function += f"# {line}\n" + dispatch_function += "\n" + + directory = directory or self.results_dir + result_folder_path = os.path.join(directory, f"{self.dispatch_id}") + Path(result_folder_path).mkdir(parents=True, exist_ok=True) + + # Accumulate the tasks and workflow in a string + topo_sorted_graph = self.lattice.transport_graph.get_topologically_sorted_graph() + functions_added = [] + for level in topo_sorted_graph: + for nodes in level: + function = self.lattice.transport_graph.get_node_value( + nodes, value_key="function" + ).get_deserialized() + if function is not None and function.__name__ not in functions_added: + + dispatch_function += self.lattice.transport_graph.get_node_value( + nodes, value_key="function_string" + ) + functions_added.append(function.__name__) + + lattice_function_str = convert_to_lattice_function_call( + self.lattice.workflow_function_string, + self.lattice.workflow_function.__name__, + self.inputs, + ) + dispatch_function += lattice_function_str + + with open(os.path.join(result_folder_path, "dispatch_source.py"), "w") as f: + f.write(dispatch_function) diff --git a/covalent/_results_manager/results_manager.py b/covalent/_results_manager/results_manager.py new file mode 100644 index 000000000..88c13c108 --- /dev/null +++ b/covalent/_results_manager/results_manager.py @@ -0,0 +1,202 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + + +import os +import pickle as _pickle +from pathlib import Path +from typing import List, Optional, Union + +import cloudpickle as pickle + +from .._shared_files.config import get_config +from .result import Result + + +def get_result( + dispatch_id: str, results_dir: str = get_config("dispatcher.results_dir"), wait: bool = False +) -> Result: + """ + Get the results of a dispatch from a file. + + Args: + dispatch_id: The dispatch id of the result. + results_dir: The directory where the results are stored in dispatch id named folders. + wait: Whether to wait for the result to be completed/failed, default is False. + + Returns: + result_object: The result from the file. + + Raises: + RuntimeError: If the result is not ready to read yet. + FileNotFoundError: If the result file is not found. + """ + + try: + result_object = _get_result_from_file(dispatch_id, results_dir, wait) + + except FileNotFoundError: + raise FileNotFoundError( + f"Result was not found in the specified directory. Please make sure it hasn't been moved or try a different directory than {results_dir}." + ) + + return result_object + + +def _get_result_from_file( + dispatch_id: str, results_dir: str = get_config("dispatcher.results_dir"), wait: bool = False +) -> Result: + + """ + Internal function to get the results of a dispatch from a file without checking if it is ready to read. + + Args: + dispatch_id: The dispatch id of the result. + results_dir: The directory where the results are stored in dispatch id named folders. + wait: Whether to wait for the result to be completed/failed, default is False. + + Returns: + result_object: The result from the file. + + Raises: + RuntimeError: If the result is found but is not ready to read yet. + FileNotFoundError: If the result is not found. + """ + + results_dir_expanded = str(Path(results_dir).expanduser().resolve()) + result_dir = os.path.join(results_dir_expanded, f"{dispatch_id}") + + while True: + try: + with open(os.path.join(result_dir, "result.pkl"), "rb") as f: + result = pickle.loads(f.read()) + + if not wait: + return result + elif result.status in [Result.COMPLETED, Result.FAILED, Result.CANCELLED]: + return result + except (FileNotFoundError, EOFError, _pickle.UnpicklingError): + if wait: + continue + raise RuntimeError( + "Result not ready to read yet. Please wait for a couple of seconds." + ) + + +def _delete_result( + dispatch_id: str, results_dir: str = get_config("dispatcher.results_dir") +) -> None: + """ + Internal function to delete the result. + + Args: + dispatch_id: The dispatch id of the result. + results_dir: The directory where the results are stored in dispatch id named folders. + + Returns: + None + + Raises: + FileNotFoundError: If the result file is not found. + """ + + import shutil + + result_folder_path = os.path.join(results_dir, f"{dispatch_id}") + + if os.path.exists(result_folder_path): + shutil.rmtree(result_folder_path, ignore_errors=True) + + try: + os.rmdir(results_dir) + except OSError: + pass + + +def redispatch_result(result_object: Result, dispatcher: str = None) -> str: + """ + Redispatch the result as a new dispatch. + + Args: + result_object: The result object to be redispatched. + dispatcher: The address to the dispatcher in the form of hostname:port, e.g. "localhost:8080". + + Returns: + dispatch_id: The dispatch id of the new dispatch. + """ + + result_object._lattice.metadata["dispatcher"] = ( + dispatcher or result_object.lattice.metadata["dispatcher"] + ) + + return result_object.lattice._server_dispatch(result_object) + + +def sync( + dispatch_id: Optional[Union[List[str], str]] = None, + results_dir: Optional[str] = get_config("dispatcher.results_dir"), +) -> None: + """ + Synchronization call. Returns when one or more dispatches have completed. + + Args: + dispatch_id: One or more dispatch IDs to wait for before returning. + results_dir: The directory where results objects are stored. + + Returns: + None + """ + + if isinstance(dispatch_id, str): + _get_result_from_file(dispatch_id, results_dir, True) + elif isinstance(dispatch_id, list): + for d in dispatch_id: + _get_result_from_file(d, results_dir, True) + else: + from glob import glob + + dirs = glob(f"{results_dir}/*/") + for d in dirs: + dispatch_id = os.path.basename(d.rstrip("/")) + _get_result_from_file(dispatch_id, results_dir, True) + + +def cancel( + dispatch_id: str, + dispatcher: str = get_config("dispatcher.address") + ":" + str(get_config("dispatcher.port")), +) -> str: + """ + Cancel a running dispatch. + + Args: + dispatch_id: The dispatch id of the dispatch to be cancelled. + dispatcher: The address to the dispatcher in the form of hostname:port, e.g. "localhost:8080". + + Returns: + None + """ + + import requests + + url = "http://" + dispatcher + "/api/cancel" + + r = requests.post(url, data=dispatch_id.encode("utf-8")) + r.raise_for_status() + return r.content.decode("utf-8").strip().replace('"', "") diff --git a/covalent/_results_manager/utils.py b/covalent/_results_manager/utils.py new file mode 100644 index 000000000..9c736bf58 --- /dev/null +++ b/covalent/_results_manager/utils.py @@ -0,0 +1,43 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Utility functions for results manager.""" + + +def convert_to_lattice_function_call( + lattice_function_string: str, lattice_function_name: str, inputs: dict +) -> str: + """ + Converts a lattice function string to a function call string inside + `__name__` condition as well. + + Args: + lattice_function_string: The lattice function string to convert. + lattice_function_name: The name of the lattice function. + inputs: The inputs to the lattice function. + + Returns: + function_call_str: The converted lattice function string. + """ + + inp = "".join(key + "=" + str(value) + ", " for key, value in inputs.items())[:-2] + function_call_str = lattice_function_string + function_call_str += f'if __name__ == "__main__":\n {lattice_function_name}({inp})\n' + return function_call_str diff --git a/covalent/_shared_files/__init__.py b/covalent/_shared_files/__init__.py new file mode 100644 index 000000000..edb268b88 --- /dev/null +++ b/covalent/_shared_files/__init__.py @@ -0,0 +1,23 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Import shared utils.""" + +from .defaults import _DEFAULT_CONSTRAINT_VALUES diff --git a/covalent/_shared_files/config.py b/covalent/_shared_files/config.py new file mode 100644 index 000000000..610ee6e00 --- /dev/null +++ b/covalent/_shared_files/config.py @@ -0,0 +1,213 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +import os +import shutil +from functools import reduce +from operator import getitem +from pathlib import Path +from typing import Any, Dict, List, Optional, Union + +import toml + +"""Configuration manager.""" + + +class _ConfigManager: + """Configuration manager class object. + + This class is used to manage an in-memory copy of a TOML configuration file. + """ + + def __init__(self) -> None: + config_dir = ( + os.environ.get("COVALENT_CONFIG_DIR") + or (os.environ.get("XDG_CONFIG_DIR") or (os.environ["HOME"] + "/.config")) + ) + "/covalent" + self.config_file = f"{config_dir}/covalent.conf" + + if os.path.exists(self.config_file): + self.read_config() + else: + Path(config_dir).mkdir(parents=True, exist_ok=True) + + self.generate_default_config() + self.write_config() + + Path(self.get("sdk.log_dir")).mkdir(parents=True, exist_ok=True) + Path(self.get("dispatcher.cache_dir")).mkdir(parents=True, exist_ok=True) + Path(self.get("dispatcher.results_dir")).mkdir(parents=True, exist_ok=True) + Path(self.get("dispatcher.log_dir")).mkdir(parents=True, exist_ok=True) + Path(self.get("user_interface.log_dir")).mkdir(parents=True, exist_ok=True) + + def generate_default_config(self) -> None: + """ + Load the default configuration into memory. + + Args: + None + + Returns: + None + """ + + from .defaults import _DEFAULT_CONFIG + + self.config_data = _DEFAULT_CONFIG + + def read_config(self) -> None: + """ + Read the configuration from file. + + Args: + None + + Returns: + None + """ + + self.config_data = toml.load(self.config_file) + + def write_config(self) -> None: + """ + Write the configuration to file. + + Args: + None + + Returns: + None + """ + + with open(self.config_file, "w") as f: + toml.dump(self.config_data, f) + + def purge_config(self) -> None: + """ + Purge the configuration directory. + + Args: + None + + Returns: + None + """ + + shutil.rmtree(os.path.dirname(self.config_file), ignore_errors=True) + + def get(self, key: str) -> Any: + """ + Return a value given a dictionary key. + + Args: + key: Key value in period-delimited format, e.g., config[dispatcher][port] + is queried by passing "dispatcher.port" as the key. + + Returns: + value: The corresponding configuration value, usually a string or int. + """ + + return reduce(getitem, key.split("."), self.config_data) + + def set(self, key: str, value: Any) -> None: + """ + Set a key-value pair in the configuration dictionary. + + Args: + key: Key value in period-delimited format. + value: The corresponding configuration setting. + + Returns: + None + """ + + keys = key.split(".") + reduce(getitem, keys[:-1], self.config_data)[keys[-1]] = value + + +_config_manager = _ConfigManager() + + +def set_config(new_config: Union[Dict, str], new_value: Optional[Any] = None) -> None: + """ + Update the configuration. + + Users may pass a dictionary of new settings, or a string key with a value to set + a single configuration setting. + + Args: + new_config: The new configuration dictionary, or a string key name. + new_value: A new configuration value, if the first argument is a string. + + Returns: + None + """ + + if isinstance(new_config, str): + _config_manager.set(new_config, new_value) + else: + for key, value in new_config.items(): + _config_manager.set(key, value) + _config_manager.write_config() + + +def get_config(entries: Union[str, List] = []) -> Union[Dict, Union[str, int]]: + """ + Return a configuration setting. + + Invocation with no arguments returns the full configuration description; with a + list of arguments returns a dictionary of configuration settings; with a string + key name returns the corresponding value for a single setting. + + Args: + entries: A string or list of strings specifying key names. + + Returns: + config: A dictionary or string describing the corresponding configuration + settings. + """ + + if isinstance(entries, List) and len(entries) == 0: + # If no arguments are passed, return the full configuration as a dict + return _config_manager.config_data + elif isinstance(entries, List) and len(entries) == 1: + # If the argument is a single key in a List, return the corresponding value + return _config_manager.get(entries[0]) + elif isinstance(entries, str): + # If the argument is a string key, return the corresponding value + return _config_manager.get(entries) + else: + # If a set of keys are passed, return a corresponding dict of key-value pairs + values = [_config_manager.get(entry) for entry in entries] + return dict(zip(entries, values)) + + +def reload_config() -> None: + """ + Reload the configuration from the TOML file. + + Args: + None + + Returns: + None + """ + + _config_manager.read_config() diff --git a/covalent/_shared_files/context_managers.py b/covalent/_shared_files/context_managers.py new file mode 100644 index 000000000..5be64e754 --- /dev/null +++ b/covalent/_shared_files/context_managers.py @@ -0,0 +1,133 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Covalent context managers.""" + +import threading +from contextlib import contextmanager +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from .._shared_files.util_classes import DispatchInfo + from .._workflow.lattice import Lattice + + +class ActiveLatticeManager(threading.local): + """ + The active lattice manager is used to determine whether an electron is being "called" + from inside or outside a lattice. The lattice "claims" itself as active before electrons + are called and "unclaims" itself afterwards. The claim mechanism is managed as a standard + python context manager. The electron will get_active_lattice from within the context and + bind itself to the transport_graph. The electron should NOT retain any part of the lattice + or transport graph. + + Since threading.local is being subclassed here, this class is thread-safe. + """ + + def __init__(self) -> None: + self._active_lattice = None + + def get_active_lattice(self) -> "Lattice": + """ + Return the active lattice. + + Args: + None + + Returns: + active_lattice: The active lattice. + """ + + return self._active_lattice + + @contextmanager + def claim(self, lattice: "Lattice") -> None: + """ + Claim the given lattice as active. + + Args: + lattice: The lattice to claim. + + Returns: + None + + Raises: + ValueError: If the lattice is already claimed. + ValueError: If an attempt was made to unset lattice when it wasn't even set. + """ + + if self._active_lattice: + raise ValueError( + f"There is already an active lattice: {self._active_lattice.workflow_function.__name__}" + ) + self._active_lattice = lattice + try: + yield None + finally: + if not self._active_lattice: + raise ValueError("Cannot unset the active lattice if nothing is set.") + self._active_lattice = None + + +class ActiveDispatchInfoManager: + """ + The active dispatch info manager is used to maintain a single instance of dispatch information + which can be used by any of the executors or when required inside the electron execution. + For example, the lattice level details, such as the total budget assigned, or total time allotted + for the whole lattice execution, are not accessible inside the electron at the time of dispatching. + If they are required at the time of electron execution, this manager is used to provide access + to information like that. + """ + + def __init__(self) -> None: + self._active_dispatch_info = None + + def get_active_dispatch_info(self) -> "DispatchInfo": + """ + Returns the active dispatch info. + + Args: + None + + Returns: + active_dispatch_info: The active dispatch info. + """ + + return self._active_dispatch_info + + @contextmanager + def claim(self, dispatch_info) -> None: + """ + Claims the given dispatch info as active. + + Args: + dispatch_info: The dispatch info object to claim. + + Returns: + None + """ + + self._active_dispatch_info = dispatch_info + yield + self._active_dispatch_info = None + + +active_lattice_manager = ActiveLatticeManager() +active_dispatch_info_manager = ActiveDispatchInfoManager() diff --git a/covalent/_shared_files/defaults.py b/covalent/_shared_files/defaults.py new file mode 100644 index 000000000..b8fb26e9d --- /dev/null +++ b/covalent/_shared_files/defaults.py @@ -0,0 +1,93 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Create custom sentinels and defaults for Covalent""" + +import os + +import sentinel + +prefix_separator = ":" + +parameter_prefix = f"{prefix_separator}parameter{prefix_separator}" +electron_list_prefix = f"{prefix_separator}electron_list{prefix_separator}" +electron_dict_prefix = f"{prefix_separator}electron_dict{prefix_separator}" +subscript_prefix = f"{prefix_separator}subscripted{prefix_separator}" +generator_prefix = f"{prefix_separator}generated{prefix_separator}" +sublattice_prefix = f"{prefix_separator}sublattice{prefix_separator}" +attr_prefix = f"{prefix_separator}attribute{prefix_separator}" + +exclude_from_postprocess = [attr_prefix, subscript_prefix, generator_prefix] + +# Default configuration settings +_DEFAULT_CONFIG = { + "sdk": { + "log_dir": ( + os.environ.get("COVALENT_LOGDIR") + or (os.environ.get("XDG_CACHE_HOME") or (os.environ["HOME"] + "/.cache")) + ) + + "/covalent", + "log_level": os.environ.get("LOGLEVEL", "WARNING").lower(), + "enable_logging": os.environ.get("COVALENT_LOG_TO_FILE", "false").lower(), + }, + "dispatcher": { + "address": "0.0.0.0", + "port": 48008, + "cache_dir": (os.environ.get("XDG_CACHE_HOME") or (os.environ["HOME"] + "/.cache")) + + "/covalent", + "results_dir": os.environ.get("COVALENT_RESULTS_DIR", "results"), + "log_dir": (os.environ.get("XDG_CACHE_HOME") or (os.environ["HOME"] + "/.cache")) + + "/covalent", + }, + "user_interface": { + "address": "0.0.0.0", + "port": 47007, + "log_dir": (os.environ.get("XDG_CACHE_HOME") or (os.environ["HOME"] + "/.cache")) + + "/covalent", + }, + "executors": { + "local": { + "log_stdout": "stdout.log", + "log_stderr": "stderr.log", + "cache_dir": "/tmp/covalent", + }, + # Add entries for custom executors here + }, +} + +# Metadata which may influence execution behavior +default_constraints_dict = { + "schedule": False, + "num_cpu": 1, + "cpu_feature_set": [], + "num_gpu": 0, + "gpu_type": "", + "gpu_compute_capability": [], + "memory": "1G", + "backend": "local", + "time_limit": "00-00:00:00", + "budget": 0, + "conda_env": "", +} + +_DEFAULT_CONSTRAINT_VALUES = sentinel.create( + "_DEFAULT_CONSTRAINT_VALUES", + cls_dict=default_constraints_dict.copy(), +) diff --git a/covalent/_shared_files/logger.py b/covalent/_shared_files/logger.py new file mode 100644 index 000000000..fb52f4dff --- /dev/null +++ b/covalent/_shared_files/logger.py @@ -0,0 +1,76 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Module for logging errors, warnings, and debug statements.""" + +import logging +import os +import sys +import time + +from .config import get_config + +logging.Formatter.converter = time.gmtime + +app_log = logging.getLogger(__name__) + +log_level = get_config("sdk.log_level").upper() +app_log.setLevel(log_level) + +# Set the format +stream_formatter = logging.Formatter( + "%(filename)s: " + "Line " "%(lineno)s in %(funcName)s:\n" + "%(levelname)s - %(message)s" +) + +stream_handler = logging.StreamHandler() +stream_handler.setLevel(log_level) +stream_handler.setFormatter(stream_formatter) +stream_handler.stream = sys.stdout + +app_log.addHandler(stream_handler) +app_log.propagate = False + +# Show stack traces +log_stack_info = os.environ.get("LOGSTACK", "TRUE").upper() == "TRUE" +# Show debug statements +log_debug_info = os.environ.get("LOGDEBUG", "FALSE").upper() == "TRUE" + +# Also log to file +log_to_file = get_config("sdk.enable_logging").upper() == "TRUE" + +if log_to_file: + import datetime + import logging.handlers + + log_dir = get_config("sdk.log_dir") + os.makedirs(log_dir, exist_ok=True) + + timestamp = datetime.datetime.utcnow().strftime("%Y-%m-%d_%H.%M.%S_UTC") + log_file = os.path.join(log_dir, timestamp + ".log") + + file_handler = logging.handlers.RotatingFileHandler(log_file) + file_handler.setLevel(log_level) + file_formatter = logging.Formatter( + "%(asctime)s - " + "%(filename)s: " + "Line " + "%(lineno)s in %(funcName)s:\n" + "%(levelname)s - %(message)s", + "%Y-%m-%d %H:%M:%S UTC", + ) + file_handler.setFormatter(file_formatter) + app_log.addHandler(file_handler) diff --git a/covalent/_shared_files/util_classes.py b/covalent/_shared_files/util_classes.py new file mode 100644 index 000000000..b9211c762 --- /dev/null +++ b/covalent/_shared_files/util_classes.py @@ -0,0 +1,70 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + + +from dataclasses import dataclass +from typing import Any, Dict, NamedTuple + + +@dataclass +class Status: + STATUS: str + + def __bool__(self): + """ + Return True if the status is not "NEW_OBJECT" + """ + + return self.STATUS != "NEW_OBJECT" + + def __str__(self) -> str: + return self.STATUS + + +class RESULT_STATUS: + NEW_OBJECT = Status("NEW_OBJECT") + COMPLETED = Status("COMPLETED") + FAILED = Status("FAILED") + RUNNING = Status("RUNNING") + CANCELLED = Status("CANCELLED") + + +class TaskExecutionMetadata(NamedTuple): + """ + Metadata about a task execution. + + Attributes: + selected_executor: The name of the executor that was selected for this task. + execution_args: The arguments that were passed to the executor. + """ + + selected_executor: Any + execution_args: Dict + + +class DispatchInfo(NamedTuple): + """ + Information about a dispatch to be shared to a task post dispatch. + + Attributes: + dispatch_id: Dispatch id of the dispatch. + """ + + dispatch_id: str diff --git a/covalent/_shared_files/utils.py b/covalent/_shared_files/utils.py new file mode 100644 index 000000000..ebdaf7dc6 --- /dev/null +++ b/covalent/_shared_files/utils.py @@ -0,0 +1,241 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""General utils for Covalent.""" + +import ast +import inspect +from datetime import timedelta +from io import TextIOWrapper +from typing import Callable, Dict, Set, Union + +from . import logger + +app_log = logger.app_log +log_stack_info = logger.log_stack_info + + +def get_timedelta(time_limit: str) -> timedelta: + """ + Get timedelta from a compatible time limit string passed to the lattice/electron decorator. + + Args: + time_limit: The time limit string. + + Returns: + timedelta: The `datetime.timedelta` object. + """ + + days, hours, minutes, seconds = time_limit.split("-")[0], *time_limit.split("-")[1].split(":") + return timedelta( + days=int(days), + hours=int(hours), + minutes=int(minutes), + seconds=int(seconds), + ) + + +def reformat(t: int) -> str: + """ + Reformat an integer to a readable time-like string. For example, if t = 1, return "01". + + Args: + t: The integer to reformat. + + Returns: + ref_string: The reformatted string. + """ + + return f"0{t}" if len(str(t)) == 1 else str(t) + + +def get_time(time_delta: timedelta) -> str: + """ + Get a compatible time string from a timedelta object. + + Args: + time_delta: The timedelta object. + + Returns: + time_string: The compatible reformatted time string. + """ + + days = reformat(time_delta.days) + hours = reformat(time_delta.seconds // 3600) + minutes = reformat((time_delta.seconds // 60) % 60) + seconds = reformat(time_delta.seconds % 60) + return f"{days}-{hours}:{minutes}:{seconds}" + + +def get_serialized_function_str(function): + """ + Generates a string representation of a function definition + including the decorators on it. + + Args: + function: The function whose definition is to be convert to a string. + + Returns: + function_str: The string representation of the function definition. + """ + + imports = _get_imports_from_source() + ct_decorators = _get_cova_imports(imports) + + input_function = function + # If a Lattice or electron object was passed as the function input, we need the + # underlying function describing the lattice. + while hasattr(input_function, "workflow_function"): + input_function = input_function.workflow_function + + try: + # function_str is the string representation of one function, with decorators, if any. + function_str = inspect.getsource(input_function) + + # Check if the function has covalent decorators that need to be commented out. + commented_lines = set() + parsed_source = ast.parse(function_str) + for node in ast.iter_child_nodes(parsed_source): + for decorator in node.decorator_list: + start = decorator.lineno + end = decorator.end_lineno + decorator_name = "" + if hasattr(decorator, "id"): + decorator_name = decorator.id + elif hasattr(decorator, "func"): + decorator_name = decorator.func.value.id + else: + decorator_name = decorator.value.id + if decorator_name in ct_decorators: + for i in range(start - 1, end): + commented_lines.add(i) + + function_str_list = function_str.split("\n") + for i in range(len(function_str_list)): + if i in commented_lines: + line = function_str_list[i].lstrip() + function_str_list[i] = f"# {function_str_list[i]}" + function_str = "\n".join(function_str_list) + except Exception: + function_str = f"# {function.__name__} was not inspectable" + return function_str + "\n\n" + + +def _get_cova_imports(imports_set: Set[Union[ast.Import, ast.ImportFrom]]) -> Set[str]: + """Get a set of Covalent-related imports (and aliases) from a set of imports. + + Args: + imports_set: A complete set of modules that have been imported. + + Returns: + imports: A set of Covalent-related imports, inluding any aliases. + """ + + ct_imports = set() + for node in imports_set: + if isinstance(node, ast.Import): + for i in range(len(node.names)): + if node.names[i].name == "covalent": + if node.names[i].asname is None: + ct_imports.add("covalent") + else: + ct_imports.add(node.names[i].asname) + elif isinstance(node, ast.ImportFrom): + if node.module == "covalent": + for i in range(len(node.names)): + if node.names[i].asname is None: + ct_imports.add(node.names[i].name) + else: + ct_imports.add(node.names[i].asname) + + return ct_imports + + +def _get_imports_from_source( + source: Union[str, TextIOWrapper] = "", + is_filename: bool = True, + imports: set = set(), +) -> Set[Union[ast.Import, ast.ImportFrom]]: + """Get (or add to) a set of imports from a source file. + + Args: + source: The input source code (as a string), filename or file-handler object. If empty + all files in scope are scanned. + is_filename: If input source is a non-empty string, this denotes whether it is the source code + itself, or a filename. + imports: If non-empty, any imports found are added to this set and returned. + + Returns: + imports: A set of imports (ast.node objects) found in the specified module code file. + """ + + if isinstance(source, str): + if source == "": + for frame_info in inspect.stack(): + frame = frame_info.frame + try: + source = inspect.getsource(frame) + imports = _get_imports_from_source( + source=source, is_filename=False, imports=imports + ) + except (IndentationError, OSError) as e: + # This is scanning all files that are utilized. We don't want any minor error, that + # possibly could come from outside the Covalent code-base, to derail the process. + app_log.debug(e) + elif is_filename: + with open(source, "r") as fh: + source = fh.read() + else: + # source is the actual source as a str object + pass + elif isinstance(source, TextIOWrapper): + source = source.read() + else: + raise TypeError + + try: + parsed_source = ast.parse(source) + for node in ast.iter_child_nodes(parsed_source): + if isinstance(node, (ast.Import, ast.ImportFrom)): + imports.add(node) + except IndentationError as e: + app_log.debug(e) + + return imports + + +def required_params_passed(func: Callable, kwargs: Dict) -> bool: + """Check to see that values for all parameters without default values have been passed. + + Args: + func: Callable function. + kwargs: Parameter list with passed values. + + Returns: + status: Whether all the parameters required for the callable function has been passed. + """ + + required_arg_set = set({}) + sig = inspect.signature(func) + for param in sig.parameters.values(): + if param.default is param.empty: + required_arg_set.add(str(param)) + + return required_arg_set.issubset(set(kwargs.keys())) diff --git a/covalent/_workflow/__init__.py b/covalent/_workflow/__init__.py new file mode 100644 index 000000000..9927b3a6c --- /dev/null +++ b/covalent/_workflow/__init__.py @@ -0,0 +1,24 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Import workflow utilities.""" + +from .electron import electron +from .lattice import lattice diff --git a/covalent/_workflow/electron.py b/covalent/_workflow/electron.py new file mode 100644 index 000000000..ff0ac3a26 --- /dev/null +++ b/covalent/_workflow/electron.py @@ -0,0 +1,513 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Class corresponding to computation nodes.""" + +import inspect +import operator +from functools import wraps +from typing import TYPE_CHECKING, Any, Callable, Iterable, List, Optional, Union + +from .._shared_files import logger +from .._shared_files.context_managers import active_lattice_manager +from .._shared_files.defaults import ( + _DEFAULT_CONSTRAINT_VALUES, + attr_prefix, + default_constraints_dict, + electron_dict_prefix, + electron_list_prefix, + generator_prefix, + parameter_prefix, + sublattice_prefix, + subscript_prefix, +) +from .._shared_files.utils import get_serialized_function_str +from .lattice import Lattice + +consumable_constraints = ["budget", "time_limit"] + +if TYPE_CHECKING: + from ..executor import BaseExecutor + from .transport import _TransportGraph + +app_log = logger.app_log +log_stack_info = logger.log_stack_info + + +class Electron: + """ + An electron (or task) object that is a modular component of a + work flow and is returned by :obj:`electron `. + + Attributes: + function: Function to be executed. + node_id: Node id of the electron. + metadata: Metadata to be used for the function execution. + kwargs: Keyword arguments if any. + """ + + def __init__( + self, function: Callable, node_id: int = None, metadata: dict = {}, **kwargs + ) -> None: + self.function = function + self.node_id = node_id + self.metadata = metadata + self.kwargs = kwargs + + def set_metadata(self, name: str, value: Any) -> None: + """ + Function to add/edit metadata of given name and value + to electron's metadata. + + Args: + name: Name of the metadata to be added/edited. + value: Value of the metadata to be added/edited. + + Returns: + None + """ + + self.metadata[name] = value + + def get_metadata(self, name: str) -> Any: + """ + Get value of the metadata of given name. + + Args: + name: Name of the metadata whose value is needed. + + Returns: + value: Value of the metadata of given name. + + Raises: + KeyError: If metadata of given name is not present. + """ + + return self.metadata[name] + + def get_op_function( + self, operand_1: Union[Any, "Electron"], operand_2: Union[Any, "Electron"], op: str + ) -> "Electron": + """ + Function to handle binary operations with electrons as operands. + This will not execute the operation but rather create another electron + which will be postponed to be executed according to the default electron + configuration/metadata. + + This also makes sure that if these operations are being performed outside + of a lattice, then they are performed as is. + + Args: + operand_1: First operand of the binary operation. + operand_2: Second operand of the binary operation. + op: Operator to be used in the binary operation. + + Returns: + electron: Electron object corresponding to the operation execution. + Behaves as a normal function call if outside a lattice. + """ + op_table = { + "+": operator.add, + "-": operator.sub, + "*": operator.mul, + "/": operator.truediv, + } + + def rename(op1: Any, op: str, op2: Any) -> Callable: + """ + Decorator to rename a function according + to the operation being performed. + + Args: + op1: First operand + op: Operator + op2: Second operand + + Returns: + function: Renamed decorated function. + """ + + def decorator(f): + + op1_name = op1 + if hasattr(op1, "function"): + op1_name = op1.function.__name__ + op2_name = op2 + if hasattr(op2, "function"): + op2_name = op2.function.__name__ + + f.__name__ = f"{op1_name}_{op}_{op2_name}" + return f + + return decorator + + @electron + @rename(operand_1, op, operand_2) + def func_for_op(arg_1: Union[Any, "Electron"], arg_2: Union[Any, "Electron"]) -> Any: + """ + Intermediate function for the binary operation. + + Args: + arg_1: First operand + arg_2: Second operand + + Returns: + result: Result of the binary operation. + """ + + return op_table[op](arg_1, arg_2) + + return func_for_op(arg_1=operand_1, arg_2=operand_2) + + def __add__(self, other): + return self.get_op_function(self, other, "+") + + def __radd__(self, other): + return self.__add__(other) + + def __sub__(self, other): + return self.get_op_function(self, other, "-") + + def __rsub__(self, other): + return self.get_op_function(other, self, "-") + + def __mul__(self, other): + return self.get_op_function(self, other, "*") + + def __rmul__(self, other): + return self.__mul__(other) + + def __truediv__(self, other): + return self.get_op_function(self, other, "/") + + def __rtruediv__(self, other): + return self.get_op_function(other, self, "/") + + def __int__(self): + return int() + + def __float__(self): + return float() + + def __complex__(self): + return complex() + + def __iter__(self): + + last_frame = inspect.currentframe().f_back + bytecode = last_frame.f_code.co_code + expected_unpack_values = bytecode[last_frame.f_lasti + 1] + + if expected_unpack_values < 2: + return + + for i in range(expected_unpack_values): + active_lattice = active_lattice_manager.get_active_lattice() + + if active_lattice: + try: + node_name = generator_prefix + self.function.__name__ + "()" + f"[{i}]" + + except AttributeError: + # The case when nested iter calls are made on the same electron + node_name = generator_prefix + active_lattice.transport_graph.get_node_value( + self.node_id, "name" + ) + node_name += f"[{i}]" + + node_id = active_lattice.transport_graph.add_node( + kwargs={"key": i}, + name=node_name, + function=None, + metadata=default_constraints_dict.copy(), + ) + + active_lattice.transport_graph.add_edge(self.node_id, node_id, f"[{i}]") + + yield Electron(function=None, node_id=node_id, metadata=None, key=i) + + def __getattr__(self, attr: str) -> "Electron": + # This is to handle the cases where magic functions are attempted + # to be accessed. For example, in the case of pickling, sometimes + # __getstate__ is called and we don't want to return an electron + # object in that case. + if attr.startswith("__") and attr.endswith("__"): + return super().__getattr__(attr) + + if attr == "keys": + raise AttributeError( + "`keys` attribute should not be used in Electron objects due to conflict with `dict.keys`", + "Please change the name of the attribute you want to use.", + ) + + active_lattice = active_lattice_manager.get_active_lattice() + + if active_lattice: + try: + node_name = attr_prefix + self.function.__name__ + "." + attr + except AttributeError: + node_name = attr_prefix + active_lattice.transport_graph.get_node_value( + self.node_id, "name" + ) + node_name += "." + attr + + node_id = active_lattice.transport_graph.add_node( + kwargs={"attr": attr}, + name=node_name, + function=None, + metadata=default_constraints_dict.copy(), + ) + + active_lattice.transport_graph.add_edge(self.node_id, node_id, f".{attr}") + + return Electron(function=None, node_id=node_id, metadata=None, attr=attr) + + return super().__getattr__(attr) + + def __getitem__(self, key: Union[int, str]) -> "Electron": + + active_lattice = active_lattice_manager.get_active_lattice() + + if active_lattice: + try: + node_name = subscript_prefix + self.function.__name__ + "()" + f"[{key}]" + except AttributeError: + # Nested subscripting calls are made on the same electron + node_name = subscript_prefix + active_lattice.transport_graph.get_node_value( + self.node_id, "name" + ) + node_name += f"[{key}]" + + node_id = active_lattice.transport_graph.add_node( + kwargs={"key": key}, + name=node_name, + function=None, + metadata=default_constraints_dict.copy(), + ) + + active_lattice.transport_graph.add_edge(self.node_id, node_id, f"[{key}]") + + return Electron(function=None, node_id=node_id, metadata=None, key=key) + + raise StopIteration + + def __call__(self, *args, **kwargs) -> Union[Any, "Electron"]: + """ + Function to execute the electron. + + This behaves differently if the execution call is made inside a lattice + and just adds the electron as a node to the lattice's transport graph. + + If the execution call is made outside of a lattice, then it executes the + electron as a normal function call. + + Also contains a postprocessing part where the lattice's function is executed + after all the nodes in the lattice's transport graph are executed. Then the + execution call to the electron is replaced by its corresponding result. + """ + + # Check if inside a lattice and if not, perform a direct invocation of the function + active_lattice = active_lattice_manager.get_active_lattice() + if active_lattice is None: + return self.function(*args, **kwargs) + + # Merging the args to kwargs to maintain consistency throughout the code + if self.function: + kwargs.update(dict(zip(list(inspect.signature(self.function).parameters), args))) + + if active_lattice.post_processing: + key = [k for k in active_lattice.electron_outputs if f"{self.function.__name__}" in k][ + 0 + ] + + if not key: + raise ValueError( + "dispatch_id and lattice mismatch. Please try " + "again with the correct dispatch_id." + ) + + output = active_lattice.electron_outputs[key] + del active_lattice.electron_outputs[key] + return output + + # Setting metadata for default values according to lattice's metadata + # If metadata is default, then set it to lattice's default + for k in self.metadata: + if k not in consumable_constraints and self.get_metadata(k) is getattr( + _DEFAULT_CONSTRAINT_VALUES, k + ): + self.set_metadata(k, active_lattice.get_metadata(k)) + + # Add a node to the transport graph of the active lattice + self.node_id = active_lattice.transport_graph.add_node( + kwargs=kwargs, + name=sublattice_prefix + self.function.__name__ + if isinstance(self.function, Lattice) + else self.function.__name__, + function=self.function, + metadata=self.metadata.copy(), + ) + + # Add function string + active_lattice.transport_graph.set_node_value( + self.node_id, "function_string", get_serialized_function_str(self.function) + ) + + for key, value in kwargs.items(): + self.add_node_for_nested_iterables( + value, self.node_id, key, active_lattice.transport_graph + ) + + return Electron( + self.function, + metadata=self.metadata, + node_id=self.node_id, + **kwargs, + ) + + def add_node_to_graph( + self, graph: "_TransportGraph", prefix: str, key: str, value: Iterable + ) -> int: + """ + Adds the node to lattice's transport graph in the case + where a collection of electrons is passed as an argument + to another electron. + + Args: + graph: Transport graph of the lattice + prefix: Prefix of the node + key: Key of the node kwargs + value: Value of the node kwargs + + Returns: + node_id: Node id of the added node + """ + + @electron + def to_electron_collection(**x): + return list(x.values())[0] + + node_id = graph.add_node( + kwargs={key: value}, + name=prefix, + function=to_electron_collection, + metadata=default_constraints_dict.copy(), + ) + + graph.set_node_value( + node_id, "function_string", get_serialized_function_str(to_electron_collection) + ) + + return node_id + + def add_node_for_nested_iterables( + self, + some_value: Union[Any, "Electron"], + node_id: int, + key: str, + transport_graph: "_TransportGraph", + ): + """ + Adds a node along with connecting edges for all the arguments to the electron. + + Args: + some_value: Value of the node kwarg + node_id: Node number of the electron + key: Key of the node kwarg + transport_graph: Transport graph of the lattice + + Returns: + None + """ + + if isinstance(some_value, Electron): + transport_graph.add_edge(some_value.node_id, node_id, variable=key) + + elif isinstance(some_value, list): + list_node = self.add_node_to_graph( + transport_graph, electron_list_prefix, key, some_value + ) + + for v in some_value: + self.add_node_for_nested_iterables(v, list_node, key, transport_graph) + + transport_graph.add_edge(list_node, node_id, variable=key) + + elif isinstance(some_value, dict): + dict_node = self.add_node_to_graph( + transport_graph, electron_dict_prefix, key, some_value + ) + + for k, v in some_value.items(): + self.add_node_for_nested_iterables(v, dict_node, k, transport_graph) + + transport_graph.add_edge(dict_node, node_id, variable=key) + + else: + argument_kwargs = {key: some_value} + argument_node = transport_graph.add_node( + kwargs=argument_kwargs, + name=parameter_prefix + str(some_value), + function=None, + metadata=default_constraints_dict.copy(), + ) + transport_graph.add_edge(argument_node, node_id, variable=key) + + +def electron( + _func: Optional[Callable] = None, + *, + backend: Optional[ + Union[List[Union[str, "BaseExecutor"]], Union[str, "BaseExecutor"]] + ] = _DEFAULT_CONSTRAINT_VALUES.backend, + # Add custom metadata fields here +) -> Callable: + """Electron decorator to be called upon a function. Returns a new :obj:`Electron ` object. + + Args: + _func: function to be decorated + + Keyword Args: + backend: Alternative executor object to be used by the electron execution. If not passed, the local + executor is used by default. + + Returns: + :obj:`Electron ` : Electron object inside which the decorated function exists. + """ + + constraints = { + "backend": backend, + } + + def decorator_electron(func=None): + @wraps(func) + def wrapper(*args, **kwargs): + electron_object = Electron(func) + for k, v in constraints.items(): + electron_object.set_metadata(k, v) + electron_object.__doc__ = func.__doc__ + return electron_object(*args, **kwargs) + + return wrapper + + if _func is None: # decorator is called with arguments + return decorator_electron + else: # decorator is called without arguments + return decorator_electron(_func) diff --git a/covalent/_workflow/lattice.py b/covalent/_workflow/lattice.py new file mode 100644 index 000000000..506363a17 --- /dev/null +++ b/covalent/_workflow/lattice.py @@ -0,0 +1,416 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Class corresponding to computation workflow.""" + +import inspect +import os +import warnings +from contextlib import redirect_stdout +from functools import wraps +from pathlib import Path +from typing import TYPE_CHECKING, Any, Callable, List, Optional, Union + +import matplotlib.pyplot as plt +import networkx as nx + +from .._results_manager.results_manager import get_result +from .._shared_files import logger +from .._shared_files.config import get_config +from .._shared_files.context_managers import active_lattice_manager +from .._shared_files.defaults import _DEFAULT_CONSTRAINT_VALUES +from .._shared_files.utils import ( + get_serialized_function_str, + get_timedelta, + required_params_passed, +) +from .transport import _TransportGraph + +if TYPE_CHECKING: + from .._results_manager.result import Result + from ..executor import BaseExecutor + + +app_log = logger.app_log +log_stack_info = logger.log_stack_info + +consumable_constraints = [] + + +class Lattice: + """ + A lattice workflow object that holds the work flow graph and is returned by :obj:`lattice ` decorator. + + Attributes: + workflow_function: The workflow function that is decorated by :obj:`lattice ` decorator. + transport_graph: The transport graph which will be the basis on how the workflow is executed. + metadata: Dictionary of metadata of the lattice. + post_processing: Boolean to indicate if the lattice is in post processing mode or not. + kwargs: Keyword arguments passed to the workflow function. + electron_outputs: Dictionary of electron outputs received after workflow execution. + """ + + def __init__( + self, workflow_function: Callable, transport_graph: _TransportGraph = None + ) -> None: + self.workflow_function = workflow_function + self.workflow_function_string = get_serialized_function_str(self.workflow_function) + self.transport_graph = transport_graph or _TransportGraph() + self.metadata = {} + self.__name__ = self.workflow_function.__name__ + self.post_processing = False + self.kwargs = {} + self.electron_outputs = {} + + def set_metadata(self, name: str, value: Any) -> None: + """ + Function to add/edit metadata of given name and value + to lattice's metadata. + + Args: + name: Name of the metadata to be added/edited. + value: Value of the metadata to be added/edited. + + Returns: + None + """ + + self.metadata[name] = value + + def get_metadata(self, name: str) -> Any: + """ + Get value of the metadata of given name. + + Args: + name: Name of the metadata whose value is needed. + + Returns: + value: Value of the metadata of given name. + + Raises: + KeyError: If metadata of given name is not present. + """ + + return self.metadata[name] + + def build_graph(self, *args, **kwargs) -> None: + """ + Builds the transport graph for the lattice by executing the workflow + function which will trigger the call of all underlying electrons and + they will get added to the transport graph for later execution. + + Also redirects any print statements inside the lattice function to null + and ignores any exceptions caused while executing the function. + + GRAPH WILL NOT BE BUILT AFTER AN EXCEPTION HAS OCCURRED. + + Args: + *args: Positional arguments to be passed to the workflow function. + **kwargs: Keyword arguments to be passed to the workflow function. + + Returns: + None + """ + + self.transport_graph.reset() + + # Positional args are converted to kwargs + if self.workflow_function: + kwargs.update( + dict(zip(list(inspect.signature(self.workflow_function).parameters), args)) + ) + + self.kwargs = kwargs + with redirect_stdout(open(os.devnull, "w")): + with active_lattice_manager.claim(self): + try: + self.workflow_function(**kwargs) + except Exception: + warnings.warn( + "Please make sure you are not manipulating an object inside the lattice." + ) + raise + + def draw(self, ax: plt.Axes = None, *args, **kwargs) -> None: + """ + Rebuilds the graph according to the kwargs passed and draws it on the given axis. + If no axis is given then a new figure is created. + + Note: This function does `plt.show()` at the end. + + Args: + ax: Axis on which the graph is to be drawn. + *args: Positional arguments to be passed to build the graph. + **kwargs: Keyword arguments to be passed to build the graph. + + Returns: + None + """ + + # Positional args are converted to kwargs + if self.workflow_function: + kwargs.update( + dict(zip(list(inspect.signature(self.workflow_function).parameters), args)) + ) + + if required_params_passed(func=self.workflow_function, kwargs=kwargs): + self.build_graph(**kwargs) + else: + raise ValueError( + "Provide values for all the workflow function parameters without default values." + ) + + main_graph = self.transport_graph.get_internal_graph_copy() + + node_labels = nx.get_node_attributes(main_graph, "name") + + if ax is None: + _, ax = plt.subplots() + main_graph.graph["graph"] = {"rankdir": "TD"} + main_graph.graph["node"] = {"shape": "circle"} + main_graph.graph["edges"] = {"arrowsize": "4.0"} + + prog = "dot" + args = "-Gnodesep=1 -Granksep=2 -Gpad=0.1 -Grankdir=TD" + root = None + pos = nx.drawing.nx_agraph.graphviz_layout(main_graph, prog=prog, root=root, args=args) + + # Print the node number in the label as `[node number]` + for key, value in node_labels.items(): + node_labels[key] = "[" + str(key) + "]\n" + value + edge_labels = nx.get_edge_attributes(main_graph, "variable") + nx.draw( + main_graph, + pos=pos, + labels=node_labels, + node_color="w", + node_size=700, + node_shape="s", + ) + nx.draw_networkx_edge_labels(main_graph, pos, edge_labels) + plt.margins(x=0.4) + plt.tight_layout() + return ax + + def __call__(self, *args, **kwargs): + """Execute lattice as an ordinary function for testing purposes.""" + + return self.workflow_function(*args, **kwargs) + + def check_constraint_specific_sum(self, constraint_name: str, node_list: List[dict]) -> bool: + """ + Function to check whether the sum of the given constraint in each electron + are within the constraint specified for the lattice. + + Args: + constraint_name: Name of the constraint to be checked, e.g budget, timelimit, etc. + node_list: List of nodes to be checked. + + Returns: + True if the sum of constraints are within the constraint specified for the lattice, + else False. + """ + + constraint_list = [ + node["metadata"][constraint_name] if node["metadata"] else None for node in node_list + ] + + parameter_node_id = [i for i, x in enumerate(constraint_list) if not x] + + if constraint_name == "budget": + constraint_sum = sum( + cl for i, cl in enumerate(constraint_list) if i not in parameter_node_id + ) + + return constraint_sum <= self.get_metadata(constraint_name) + + elif constraint_name == "time_limit": + from datetime import timedelta + + order = self.transport_graph.get_topologically_sorted_graph() + + delta_list_parallel = [] + for node_set in order: + node_set_time_deltas = [ + get_timedelta(constraint_list[n]) + for n in node_set + if n not in parameter_node_id + ] + if node_set_time_deltas: + delta_list_parallel.append(max(node_set_time_deltas)) + + return sum(delta_list_parallel, timedelta()) <= get_timedelta( + self.get_metadata(constraint_name) + ) + + def check_consumable(self) -> None: + """ + Function to check whether all consumable constraints in all the nodes are + within the limits of what is specified for the lattice. + + Args: + None + + Returns: + None + + Raises: + ValueError: If the sum of consumable constraints in all the nodes are + not within the total limit of the lattice. + """ + + graph_copy = self.transport_graph.get_internal_graph_copy() + data = nx.readwrite.node_link_data(graph_copy) + + for constraint in consumable_constraints: + if not self.check_constraint_specific_sum(constraint, data["nodes"]): + raise ValueError( + "The sum of all electron {} constraints is greater than the lattice {} constraint".format( + constraint, constraint + ) + ) + + def dispatch(self, *args, **kwargs) -> str: + """ + Run the lattice-defined workflow with the dispatcher asynchronously. + + Args: + *args: Positional arguments to be passed to the workflow function. + **kwargs: Keyword arguments to pass to the workflow function. + + Returns: + dispatch_id: the unique id of the dispatched job obtained from the dispatcher server. + """ + + # Positional args are converted to kwargs + if self.workflow_function: + kwargs.update( + dict(zip(list(inspect.signature(self.workflow_function).parameters), args)) + ) + + from .._results_manager import Result + + self.build_graph(**kwargs) + self.check_consumable() + + # Serializing the transport graph and then passing it to the Result object + transport_graph = self.transport_graph.serialize() + self.transport_graph, transport_graph = transport_graph, self.transport_graph + + dispatch_id = self._server_dispatch(Result(self, self.metadata["results_dir"])) + + # Getting the transport graph back to the original state + self.transport_graph, transport_graph = transport_graph, self.transport_graph + + return dispatch_id + + def dispatch_sync(self, *args, **kwargs) -> "Result": + """ + Run the lattice-defined workflow with the dispatcher synchronously. + + Args: + *args: Positional arguments to be passed to the workflow function. + **kwargs: Keyword arguments to pass to the workflow function. + + Returns: + result: Result of the workflow execution. + + Note: Since it is synchronous dispatching, the result is waited for completion or failure. + """ + + # Positional args are converted to kwargs + if self.workflow_function: + kwargs.update( + dict(zip(list(inspect.signature(self.workflow_function).parameters), args)) + ) + + return get_result(self.dispatch(**kwargs), self.metadata["results_dir"], wait=True) + + def _server_dispatch(self, result_object) -> str: + """ + Run the lattice-defined workflow with the dispatcher in server. + + Args: + dispatch_id: A unique id assigned to the dispatch by the dispatcher. + """ + + import cloudpickle as pickle + import requests + + pickled_res = pickle.dumps(result_object) + test_url = "http://" + self.metadata["dispatcher"] + "/api/submit" + + r = requests.post(test_url, data=pickled_res) + r.raise_for_status() + return r.content.decode("utf-8").strip().replace('"', "") + + +def lattice( + _func: Optional[Callable] = None, + *, + backend: Optional[ + Union[List[Union[str, "BaseExecutor"]], Union[str, "BaseExecutor"]] + ] = _DEFAULT_CONSTRAINT_VALUES.backend, + dispatcher: Optional[str] = get_config("dispatcher.address") + + ":" + + str(get_config("dispatcher.port")), + results_dir: Optional[str] = get_config("dispatcher.results_dir"), + # Add custom metadata fields here + # e.g. schedule: True, whether to use a custom scheduling logic or not +) -> Lattice: + """ + Lattice decorator to be called upon a function. Returns a new `Lattice ` object. + + Args: + _func: function to be decorated + + Keyword Args: + backend: Alternative executor object to be used in the execution of each node. If not passed, the local + executor is used by default. + results_dir: Directory to store the results + + Returns: + :obj:`Lattice ` : Lattice object inside which the decorated function exists. + """ + + results_dir = str(Path(results_dir).expanduser().resolve()) + + constraints = { + "backend": backend, + "dispatcher": dispatcher, + "results_dir": results_dir, + } + + def decorator_lattice(func=None): + @wraps(func) + def wrapper_lattice(*args, **kwargs): + lattice_object = Lattice(workflow_function=func) + for k, v in constraints.items(): + lattice_object.set_metadata(k, v) + lattice_object.transport_graph.lattice_metadata = lattice_object.metadata + lattice_object.__doc__ = func.__doc__ + return lattice_object + + return wrapper_lattice() + + if _func is None: # decorator is called with arguments + return decorator_lattice + else: # decorator is called without arguments + return decorator_lattice(_func) diff --git a/covalent/_workflow/transport.py b/covalent/_workflow/transport.py new file mode 100644 index 000000000..8aae8e030 --- /dev/null +++ b/covalent/_workflow/transport.py @@ -0,0 +1,355 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Class implementation of the transport graph in the workflow graph.""" + +import base64 +import platform +from typing import Any, Callable, Dict, List + +import cloudpickle +import networkx as nx + +from .._shared_files.defaults import parameter_prefix + + +class TransportableObject: + """ + A function is converted to a transportable object by serializing it using cloudpickle + and then whenever executing it, the transportable object is deserialized. The object + will also contain additional info like the python version used to serialize it. + + Attributes: + _object: The serialized object. + python_version: The python version used on the client's machine. + """ + + def __init__(self, obj: Any) -> None: + self._object = base64.b64encode(cloudpickle.dumps(obj)).decode("utf-8") + self.python_version = platform.python_version() + + def get_deserialized(self) -> Callable: + """ + Get the deserialized transportable object. + + Args: + None + + Returns: + function: The deserialized object/callable function. + + """ + + return cloudpickle.loads(base64.b64decode(self._object.encode("utf-8"))) + + def get_serialized(self) -> str: + """ + Get the serialized transportable object. + + Args: + None + + Returns: + object: The serialized transportable object. + """ + + return self._object + + def serialize(self) -> bytes: + """ + Serialize the transportable object. + + Args: + None + + Returns: + pickled_object: The serialized object alongwith the python version. + """ + + return cloudpickle.dumps( + {"object": self.get_serialized(), "py_version": self.python_version} + ) + + @staticmethod + def deserialize(data) -> "TransportableObject": + """ + Deserialize the transportable object. + + Args: + data: The serialized transportable object. + + Returns: + object: The deserialized transportable object. + """ + + obj = cloudpickle.loads(data) + sc = TransportableObject(None) + sc._object = obj["object"] + sc.python_version = obj["py_version"] + return sc + + +class _TransportGraph: + """ + A TransportGraph is the most essential part of the whole workflow. This contains + all the information about each electron and lattice required for determining how, + when, and where to execute the workflow. The TransportGraph contains a directed graph + which is used to determine the execution order of the nodes. Each node in this graph + is an electron which is ready to be executed. + + Attributes: + _graph: The directed graph object of type networkx.DiGraph(). + lattice_metadata: The lattice metadata of the transport graph. + """ + + def __init__(self) -> None: + self._graph = nx.DiGraph() + self.lattice_metadata = None + + def add_node(self, name: str, kwargs: Dict, function: Callable, metadata: Dict) -> int: + """ + Adds a node to the graph. + + Args: + name: The name of the node. + kwargs: The keyword arguments to be passed to the function. + function: The function to be executed. + metadata: The metadata of the node. + + Returns: + node_key: The node id. + """ + + node_id = len(self._graph.nodes) + self._graph.add_node( + node_id, + name=name, + kwargs=kwargs, + function=TransportableObject(function), + metadata=metadata, + ) + return node_id + + def add_edge(self, x: int, y: int, variable: Any) -> None: + """ + Add an edge to the graph and assigns a variable to it. + + Args: + x: The node id for first node. + y: The node id for second node. + variable: The variable to be assigned to the edge. + + Returns: + None + + Raises: + ValueError: If the edge already exists. + """ + + self._graph.add_edge(x, y, variable=variable) + + def reset(self) -> None: + """ + Resets the graph. + + Args: + None + + Returns: + None + """ + + self._graph = nx.DiGraph() + + def get_topologically_sorted_graph(self) -> List[List[int]]: + """ + Generates a list of node ids in the hierarchical + order of their position in the graph. Taking care + of dependencies of each node. Allows for parrallel + execution of nodes which are at the same level. + + Args: + None + + Returns: + sorted_nodes: List of node ids where nodes + belonging to the same level are + grouped together. + """ + + _g = self._graph.copy() + res = [] + while _g: + zero_indegree = [v for v, d in _g.in_degree() if d == 0] + res.append(zero_indegree) + _g.remove_nodes_from(zero_indegree) + return res + + def get_node_value(self, node_key: int, value_key: str) -> Any: + """ + Get a specific value from a node depending upon the value key. + + Args: + node_key: The node id. + value_key: The value key. + + Returns: + value: The value from the node stored at the value key. + + Raises: + KeyError: If the value key is not found. + """ + + return self._graph.nodes[node_key][value_key] + + def set_node_value(self, node_key: int, value_key: int, value: Any) -> None: + """ + Set a certain value of a node. This allows for saving custom data + in the graph nodes. + + Args: + node_key: The node id. + value_key: The value key. + value: The value to be set at value_key position of the node. + + Returns: + None + + Raises: + KeyError: If the node key is not found. + """ + + self._graph.nodes[node_key][value_key] = value + + def get_edge_value(self, dep_key: int, node_key: int, value_key: str) -> Any: + """ + Get the value of an edge. + + Args: + dep_key: The node id for first node. + node_key: The node id for second node. + value_key: The value key. + + Returns: + value: The value of specified edge. + + Raises: + KeyError: If the edge is not found. + """ + + return self._graph.get_edge_data(dep_key, node_key)[value_key] + + def get_dependencies(self, node_key: int) -> list: + """ + Gets the parent node ids of a node. + + Args: + node_key: The node id. + + Returns: + parents: The dependencies of the node. + """ + + return list(self._graph.predecessors(node_key)) + + def get_internal_graph_copy(self) -> nx.DiGraph: + """ + Get a copy of the internal directed graph + to avoid modifying the original graph. + + Args: + None + + Returns: + graph: A copy of the internal directed graph. + """ + + return self._graph.copy() + + def serialize(self, metadata_only: bool = False) -> bytes: + """ + Convert transport graph object to JSON to be used in the workflow scheduler. + + Convert transport graph networkx.DiGraph object into JSON format, filter out + computation specific attributes and lastly add the lattice metadata. This also + serializes the function Callable into by base64 encoding the cloudpickled result. + + Args: + metadata_only: If true, only serialize the metadata. + + Returns: + str: json string representation of transport graph + """ + + # Convert networkx.DiGraph to a format that can be converted to json . + data = nx.readwrite.node_link_data(self._graph) + + # process each node + for idx, node in enumerate(data["nodes"]): + data["nodes"][idx]["function"] = data["nodes"][idx].pop("function").serialize() + + if metadata_only: + parameter_node_id = [ + i + for i, node in enumerate(data["nodes"]) + if node["name"].startswith(parameter_prefix) + ] + + for node in data["nodes"].copy(): + if node["id"] in parameter_node_id: + data["nodes"].remove(node) + + # Remove the fields 'function' and 'kwargs' from the scheduler workflow input data. + unwanted_fields = ["function", "args", "kwargs", "name"] + for idx, node in enumerate(data["nodes"]): + for field in unwanted_fields: + data["nodes"][idx].pop(field, None) + + # Remove the field 'variable' from the scheduler workflow input data. + for idx, node in enumerate(data["links"]): + data["links"][idx].pop("variable", None) + + data["lattice_metadata"] = self.lattice_metadata + return cloudpickle.dumps(data) + + def deserialize(self, pickled_data: bytes) -> None: + """ + Load pickled representation of transport graph into the transport graph instance. + + This overwrites anything currently set in the transport graph and deserializes + the base64 encoded cloudpickled function into a Callable. + + Args: + pickled_data: Cloudpickled representation of the transport graph + + Returns: + None + """ + + node_link_data = cloudpickle.loads(pickled_data) + if "lattice_metadata" in node_link_data: + self.lattice_metadata = node_link_data["lattice_metadata"] + + for idx, _ in enumerate(node_link_data["nodes"]): + function_ser = node_link_data["nodes"][idx].pop("function") + node_link_data["nodes"][idx]["function"] = TransportableObject.deserialize( + function_ser + ) + self._graph = nx.readwrite.node_link_graph(node_link_data) diff --git a/covalent/executor/__init__.py b/covalent/executor/__init__.py new file mode 100644 index 000000000..9f403378e --- /dev/null +++ b/covalent/executor/__init__.py @@ -0,0 +1,235 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +""" +Defines executors and provides a "manager" to get all available executors +""" + +import glob +import importlib +import inspect +import os +from typing import Any, Dict, List, Union + +import pkg_resources + +from .._shared_files import logger +from .._shared_files.config import get_config +from .base import BaseExecutor + +app_log = logger.app_log +log_stack_info = logger.log_stack_info + + +class _ExecutorManager: + """ + Executor manager to return a valid executor which can be + used as an argument to electron and lattice decorators. + + Initializing generates a list of available executor plugins. + """ + + def __init__(self) -> None: + self.generate_plugins_list() + + def generate_plugins_list(self) -> None: + """ + Generate a list of available executor plugins. + This is called automatically when the class is initialized. + + The list is stored in the executor_map attribute. + + The list of executors is generated by loading the already + installed plugins and the plugins in the executor directory. + + These executor plugins are loaded by importing the module that + contains the plugin. + + The module should have an attribute named executor_plugin_name + which is set to the class name defining the plugin. + + Args: + None + + Returns: + None + """ + + # Dictionary mapping executor name to *already-instantiated* executor + self.executor_map: Dict[str, Any] = {} + + # Dictionary mapping executor name to executor class + self.executor_plugins_map: Dict[str, Any] = {} + + plugins_path = os.path.dirname(__file__) + "/executor_plugins" + self._load_executors(plugins_path) + + # Look for executor plugins in the config directory + default_config_dir = os.environ["HOME"] + "/.config/covalent" + plugins_path = os.environ.get("COVALENT_CONFIG_DIR", default_config_dir) + plugins_path += "/executor_plugins" + self._load_executors(plugins_path) + + # Look for pip-installed plugins + self._load_installed_plugins() + + def get_executor(self, name: Union[str, BaseExecutor], new: bool = True) -> BaseExecutor: + """ + Get an executor by name. + This accepts a string like "local" or a BaseExecutor instance. + + Args: + name: The name of the executor to get. + new: If True, a new executor is created if the name is found. + + Returns: + executor: An executor object. + + Raises: + ValueError: If name is not found and new is False. + TypeError: If name is not a string or a BaseExecutor instance. + """ + + if isinstance(name, BaseExecutor): + return name + + elif isinstance(name, str): + if name in self.executor_map: + if not new: + return self.executor_map[name] + default_options = get_config(f"executors.{name}") + return self.executor_plugins_map[name](**default_options) + else: + message = f"No executor found by name: {name}." + app_log.error(message) + raise ValueError + else: + message = f"Input must be of type str or BaseExecutor, not {type(name)}" + app_log.error(message) + raise TypeError + + def _populate_executor_map_from_module(self, the_module: Any) -> None: + """ + Populate the executor map from a module. + Also checks whether `executor_plugin_name` is defined in the module. + + Args: + the_module: The module to populate the executor map from. + + Returns: + None + """ + + if not hasattr(the_module, "executor_plugin_name"): + message = f"{the_module.__name__} does not seem to have a well-defined plugin class.\n" + message += f"Specify the plugin class with 'executor_plugin_name = ' in the {the_module.__name__} module." + app_log.warning(message) + return + + # All classes loaded by the module + all_classes = inspect.getmembers(the_module, inspect.isclass) + # Classes that are defined in the module: + module_classes = [c[1] for c in all_classes if c[1].__module__ == the_module.__name__] + # The module should have a global attribute named executor_plugin_name + # which is set to the class name defining the plugin. + plugin_class = [c for c in module_classes if c.__name__ == the_module.executor_plugin_name] + + if len(plugin_class): + plugin_class = plugin_class[0] + short_name = the_module.__name__.split("/")[-1] + self.executor_map[short_name] = plugin_class() + self.executor_plugins_map[short_name] = plugin_class + else: + # The requested plugin (the_module.module_name) was not found in the module. + message = f"Requested executor plugin {the_module.executor_plugin_name} was not found in {the_module.__name__}" + app_log.warning(message) + + def _load_installed_plugins(self) -> None: + """ + Load executor plugins from pip. + Populates the executor_map and executor_plugins_map attributes. + + Args: + None + + Returns: + None + """ + + entry_points = pkg_resources.iter_entry_points("covalent_dispatcher.executor_plugins") + for entry in entry_points: + the_module = entry.load() + self._populate_executor_map_from_module(the_module) + + def _load_executors(self, executor_dir: str) -> None: + """ + Load executor plugins from a directory. + Populates the executor map and executor_plugins_map attributes. + + Args: + executor_dir: The directory to load executor plugins from. + + Returns: + None + """ + + if os.path.exists(executor_dir): + + module_files = glob.glob(os.path.join(executor_dir, "*.py")) + + for module_file in module_files: + module_name = module_file[:-3] + + # Import the module that contains the plugin + module_spec = importlib.util.spec_from_file_location(module_name, module_file) + the_module = importlib.util.module_from_spec(module_spec) + module_spec.loader.exec_module(the_module) + + self._populate_executor_map_from_module(the_module) + + def list_executors(self, regenerate: bool = False, print_names: bool = True) -> List[str]: + """ + Return and optionally print the executors that are available. + + Args: + regenerate: If True, the executor map is regenerated. + print_names: If True, executor names are printed as well. + + Returns: + A list of executor names. + """ + + if regenerate: + self.generate_plugins_list() + + executor_list = [] + for n, name in enumerate(self.executor_map, start=1): + executor_list.append(name) + if print_names: + print(f"{n}. {name}") + + return executor_list + + +_executor_manager = _ExecutorManager() + +for name in _executor_manager.executor_plugins_map: + plugin_class = _executor_manager.executor_plugins_map[name] + globals()[plugin_class.__name__] = plugin_class diff --git a/covalent/executor/base.py b/covalent/executor/base.py new file mode 100644 index 000000000..9cace7783 --- /dev/null +++ b/covalent/executor/base.py @@ -0,0 +1,314 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +""" +Class that defines the base executor template. +""" + +import os +import subprocess +import tempfile +from abc import ABC, abstractmethod +from pathlib import Path +from typing import Any, Optional, Tuple, Union + +import cloudpickle as pickle + +from .._shared_files import logger +from .._shared_files.config import get_config +from .._shared_files.context_managers import active_dispatch_info_manager +from .._shared_files.util_classes import DispatchInfo +from .._workflow.transport import TransportableObject + +app_log = logger.app_log +log_stack_info = logger.log_stack_info + + +class ExecutorResult: + output: Any + error: Union[str, Exception] + + +class BaseExecutor(ABC): + """ + Base executor class to be used for defining any executor + plugin. Subclassing this class will allow you to define + your own executor plugin which can be used in covalent. + + Note: When using a conda environment, it is assumed that + covalent with all its dependencies are also installed in + that environment. + + Attributes: + log_stdout: The path to the file to be used for redirecting stdout. + log_stderr: The path to the file to be used for redirecting stderr. + conda_env: The name of the Conda environment to be used. + cache_dir: The location used for cached files in the executor. + current_env_on_conda_fail: If True, the current environment will be used + if conda fails to activate specified env. + """ + + def __init__( + self, + log_stdout: Optional[str] = "", + log_stderr: Optional[str] = "", + conda_env: Optional[str] = "", + cache_dir: Optional[str] = "", + current_env_on_conda_fail: bool = False, + ) -> None: + self.log_stdout = log_stdout + self.log_stderr = log_stderr + self.conda_env = conda_env + self.cache_dir = cache_dir + self.current_env_on_conda_fail = current_env_on_conda_fail + self.current_env = "" + + def get_dispatch_context(self, dispatch_info) -> None: + """ + Start a context manager that will be used to + access the dispatch info for the executor. + + Args: + dispatch_info: The dispatch info to be used inside current context. + + Returns: + None + """ + + return active_dispatch_info_manager.claim(dispatch_info) + + def write_streams_to_file(self, stream_strings, filepaths, dispatch_id="") -> None: + """ + Write the contents of stdout and stderr to respective files. + + Args: + stream_strings: The stream_strings to be written to files. + filepaths: The filepaths to be used for writing the streams. + """ + + for ss, filepath in zip(stream_strings, filepaths): + if filepath: + # If it is a relative path, attach to results dir + if not Path(filepath).expanduser().is_absolute(): + filepath = os.path.join( + os.path.join(get_config("dispatcher.results_dir"), dispatch_id), filepath + ) + + filename = Path(filepath) + filename = filename.expanduser() + filename.parent.mkdir(parents=True, exist_ok=True) + filename.touch(exist_ok=True) + + with open(filepath, "a") as f: + f.write(ss) + else: + print(ss) + + @abstractmethod + def execute( + self, + function: TransportableObject, + kwargs: Any, + execution_args: dict, + dispatch_id: str, + node_id: int = -1, + ) -> Any: + """ + Execute the function with the given arguments. + This will be overriden by other executor plugins + to design how said function needs to be run. + + Args: + function: The input python function which will be executed and whose result + is ultimately returned by this function. + kwargs: Keyword arguments to be used by function. + execution_args: Executor-specific arguments. + dispatch_id: The unique identifier of the external lattice process which is + calling this function. + + Returns: + output: The result of the function execution. + """ + + raise NotImplementedError + + def execute_in_conda_env( + self, + function: TransportableObject, + kwargs: Any, + execution_args: dict, + executor_specific_exec_cmds: dict, + dispatch_info: DispatchInfo, + conda_env: str, + cache_dir: str, + ) -> Tuple[bool, Any]: + """ + Execute the function with the given arguments, in a Conda environment. + + Args: + function: The input python function which will be executed and whose result + is ultimately returned by this function. + kwargs: Keyword arguments to be used by function. + execution_args: Executor-specific arguments. + dispatch_info: Dispatch information, e.g., the dispatch ID. + conda_env: Name of a Conda environment in which to execute the task. + + Returns: + output: The result of the function execution. + """ + + if not self.get_conda_path(): + return (False, None) + + # Pickle the function + temp_filename = "" + with tempfile.NamedTemporaryFile(dir=cache_dir, delete=False) as f: + pickle.dump(function, f) + temp_filename = f.name + + result_filename = os.path.join(cache_dir, "result_" + temp_filename.split("/")[-1]) + + # Write a bash script to activate the environment + shell_commands = "#!/bin/bash\n" + + # Add any executor-specific lines: + if executor_specific_exec_cmds: + for line in executor_specific_exec_cmds: + shell_commands += line + "\n" + + # Add commands to initialize the Conda shell and activate the environment: + conda_sh = os.path.join( + os.path.dirname(self.conda_path), "..", "etc", "profile.d", "conda.sh" + ) + conda_sh = os.environ.get("CONDA_SHELL", conda_sh) + if os.path.exists(conda_sh): + shell_commands += f"source {conda_sh}\n" + else: + message = "No Conda installation found on this compute node." + app_log.warning(message) + return (False, None) + + shell_commands += f"conda activate {conda_env}\n" + shell_commands += "retval=$?\n" + shell_commands += "if [ $retval -ne 0 ]; then\n" + shell_commands += ( + f' echo "Conda environment {conda_env} is not present on this compute node."\n' + ) + shell_commands += ' echo "Please create that environment (or use an existing environment) and try again."\n' + shell_commands += " exit 99\n" + shell_commands += "fi\n\n" + + # Check Python version and give a warning if there is a mismatch: + shell_commands += "py_version=`python -V | awk '{{print $2}}'`\n" + shell_commands += f'if [[ "{function.python_version}" != "$py_version" ]]; then\n' + shell_commands += ' echo "Warning: Python version mismatch:"\n' + shell_commands += f' echo "Workflow version is {function.python_version}. Conda environment version is $py_version."\n' + shell_commands += "fi\n\n" + + shell_commands += "python - < None: + """ + Print a list of Conda environments detected on the system. + + Args: + None + + Returns: + None + """ + + self.conda_envs = [] + + env_output = subprocess.run( + ["conda", "env", "list"], capture_output=True, encoding="utf-8" + ) + + if len(env_output.stderr) > 0: + message = f"Problem in listing Conda environments:\n{env_output.stderr}" + app_log.warning(message) + return + + for line in env_output.stdout.split("\n"): + if not line.startswith("#"): + row = line.split() + if len(row) > 1: + if "*" in row: + self.current_env = row[0] + self.conda_envs.append(row[0]) + + app_log.debug(f"Conda environments:\n{self.conda_envs}") + + def get_conda_path(self) -> bool: + """ + Query the path where the conda executable can be found. + + Args: + None + + Returns: + found: True if Conda is found on the system. + """ + + self.conda_path = "" + which_conda = subprocess.run( + ["which", "conda"], capture_output=True, encoding="utf-8" + ).stdout + if which_conda == "": + message = "No Conda installation found on this compute node." + app_log.warning(message) + return False + self.conda_path = which_conda + return True diff --git a/covalent/executor/executor_plugins/local.py b/covalent/executor/executor_plugins/local.py new file mode 100644 index 000000000..3fef02fc2 --- /dev/null +++ b/covalent/executor/executor_plugins/local.py @@ -0,0 +1,125 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +""" +Module for defining a local executor that directly invokes the input python function. + +This is a plugin executor module; it is loaded if found and properly structured. +""" + +import io +from contextlib import redirect_stderr, redirect_stdout +from typing import Any + +# Relative imports are not allowed in executor plugins +from covalent._shared_files import logger +from covalent._shared_files.util_classes import DispatchInfo +from covalent._workflow.transport import TransportableObject +from covalent.executor import BaseExecutor + +# The plugin class name must be given by the executor_plugin_name attribute: +executor_plugin_name = "LocalExecutor" + +app_log = logger.app_log +log_stack_info = logger.log_stack_info + + +class LocalExecutor(BaseExecutor): + """ + Local executor class that directly invokes the input function. + """ + + def execute( + self, + function: TransportableObject, + kwargs: Any, + execution_args: dict, + dispatch_id: str, + node_id: int = -1, + ) -> Any: + """ + Executes the input function and returns the result. + + Args: + function: The input python function which will be executed and whose result + is ultimately returned by this function. + kwargs: Keyword arguments to be used by function. + execution_args: Executor-specific arguments. + dispatch_id: The unique identifier of the external lattice process which is + calling this function. + node_id: The node ID of this task in the bigger workflow graph. + + Returns: + output: The result of the executed function. + """ + + dispatch_info = DispatchInfo(dispatch_id) + + with self.get_dispatch_context(dispatch_info), redirect_stdout( + io.StringIO() + ) as stdout, redirect_stderr(io.StringIO()) as stderr: + + if self.conda_env != "": + success = False + result = None + + # Extract any executor-specific bash commands from execution_args that are + # needed. Each command should be an entry in executor_specific_execution_args. + # This executor has none. + executor_specific_exec_cmds = [] + + success, result = self.execute_in_conda_env( + function, + kwargs, + execution_args, + executor_specific_exec_cmds, + dispatch_info, + self.conda_env, + self.cache_dir, + ) + + if success: + message = f"Executed node {node_id} on Conda environment {self.conda_env}." + app_log.debug(message) + + else: + message = ( + f"Failed to execute node {node_id} on Conda environment {self.conda_env}." + ) + if self.current_env_on_conda_fail: + message += "\nExecuting on the current Conda environment." + app_log.warning(message) + fn = function.get_deserialized() + result = fn(**kwargs) + + else: + app_log.error(message) + + raise RuntimeError + + else: + fn = function.get_deserialized() + result = fn(**kwargs) + + self.write_streams_to_file( + (stdout.getvalue(), stderr.getvalue()), (self.log_stdout, self.log_stderr), dispatch_id + ) + + return (result, stdout.getvalue(), stderr.getvalue()) diff --git a/covalent_dispatcher/__init__.py b/covalent_dispatcher/__init__.py new file mode 100644 index 000000000..4da15b63f --- /dev/null +++ b/covalent_dispatcher/__init__.py @@ -0,0 +1,121 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +""" +Self-contained entry point for the dispatcher +""" + +import uuid + +from dask.distributed import Client, fire_and_forget + +from covalent._results_manager import Result +from covalent._results_manager import results_manager as rm +from covalent._workflow.transport import _TransportGraph + +try: + dask_client = Client(address="127.0.0.1:8786", timeout="1s") +except OSError: + dask_client = Client(processes=False, dashboard_address=":0") + + +def get_unique_id() -> str: + """ + Get a unique ID. + + Args: + None + + Returns: + str: Unique ID + """ + + return str(uuid.uuid4()) + + +def run_dispatcher(result_object: Result) -> str: + """ + Run the dispatcher from the lattice asynchronously using Dask. + Assign a new dispatch id to the result object and return it. + Also save the result in this initial stage to the file mentioned in the result object. + + Args: + result_object: A Result object containing necessary information for the dispatcher + to execute the workflow. + + Returns: + dispatch_id: A string containing the dispatch id of current dispatch. + """ + + if not result_object.dispatch_id: + dispatch_id = get_unique_id() + result_object._dispatch_id = dispatch_id + + transport_graph = _TransportGraph() + transport_graph.deserialize(result_object.lattice.transport_graph) + result_object._lattice.transport_graph = transport_graph + + result_object._initialize_nodes() + + result_object.save() + + from ._core import run_workflow + + fire_and_forget( + dask_client.submit( + run_workflow, + result_object.dispatch_id, + result_object.results_dir, + ) + ) + + return dispatch_id + + +def get_result(dispatch_id: str, results_dir: str, wait: bool) -> Result: + """ + Return the results of the dispatcher. + + Args: + dispatch_id: Dispatch id of the result to be fetched. + results_dir: Path of the results directory. + wait: Whether to wait for the result to be complete/fail before returning. + + Returns: + result: Result object containing the results of the said dispatch. + """ + + return rm._get_result_from_file(dispatch_id, results_dir, wait) + + +def cancel_running_dispatch(dispatch_id: str) -> None: + """ + Cancels a running dispatch job. + + Args: + dispatch_id: Dispatch id of the dispatch to be cancelled. + + Returns: + None + """ + + from ._core import cancel_workflow + + cancel_workflow(dispatch_id) diff --git a/covalent_dispatcher/_cli/__init__.py b/covalent_dispatcher/_cli/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/covalent_dispatcher/_cli/cli.py b/covalent_dispatcher/_cli/cli.py new file mode 100644 index 000000000..d45c1b193 --- /dev/null +++ b/covalent_dispatcher/_cli/cli.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Covalent CLI Tool.""" + +import click + +from .service import purge, restart, start, status, stop + + +# Main entrypoint +@click.group(invoke_without_command=True) +@click.option("-v", "--version", is_flag=True, help="Display version information.") +@click.pass_context +def cli(ctx: click.Context, version: bool) -> None: + """ + Covalent CLI tool used to manage the dispatcher and UI servers. + """ + if version: + from covalent import __version__ + + click.echo("covalent: Covalent Workflow CLI Tool") + click.echo("Copyright (C) 2021 Agnostiq Inc.") + click.echo("Built using Python 3.8 (Platform: x86_64-linux)") + click.echo(f"Release version {__version__}") + elif ctx.invoked_subcommand is None: + # Display the help menu if no command was provided + ctx = click.get_current_context() + click.echo(ctx.get_help()) + + +# Server management +cli.add_command(start) +cli.add_command(stop) +cli.add_command(restart) +cli.add_command(status) +cli.add_command(purge) + +if __name__ == "__main__": + cli() diff --git a/covalent_dispatcher/_cli/service.py b/covalent_dispatcher/_cli/service.py new file mode 100644 index 000000000..f76d71c07 --- /dev/null +++ b/covalent_dispatcher/_cli/service.py @@ -0,0 +1,396 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +"""Covalent CLI Tool - Service Management.""" + +import os +import shutil +import signal +import socket +from subprocess import Popen +from typing import Optional + +import click +import psutil + +import covalent_dispatcher +from covalent._shared_files.config import get_config, set_config + +DISPATCHER_PIDFILE = get_config("dispatcher.cache_dir") + "/dispatcher.pid" +DISPATCHER_LOGFILE = get_config("dispatcher.log_dir") + "/dispatcher.log" +DISPATCHER_SRVDIR = os.path.dirname(os.path.abspath(__file__)) + "/../_service" + +UI_PIDFILE = get_config("dispatcher.cache_dir") + "/ui.pid" +UI_LOGFILE = get_config("user_interface.log_dir") + "/covalent_ui.log" +UI_SRVDIR = os.path.dirname(os.path.abspath(__file__)) + "/../../covalent_ui" + + +def _read_pid(filename: str) -> int: + """ + Read the process ID from file. + + Args: + filename: The path to the file to read the process ID from. + + Returns: + The process ID. + """ + + try: + pid = int(open(filename, "r").readline()) + except FileNotFoundError: + pid = -1 + + return pid + + +def _rm_pid_file(filename: str) -> None: + """ + Remove a process ID file safely. + + Args: + filename: The path to the file that will be removed. + + Returns: + None + """ + + try: + os.remove(filename) + except OSError: + pass + + +def _port_from_pid(pid: int) -> int: + """ + Return the port in use by a process. + + Args: + pid: Process ID. + + Returns: + port: Port in use by the process. + """ + + try: + port = psutil.Process(pid).connections()[0].laddr[1] + except (psutil.NoSuchProcess, ValueError): + port = None + + return port + + +def _next_available_port(requested_port: int) -> int: + """ + Return the next available port not in use. + + Args: + requested_port: Port requested for a socket. + + Returns: + assigned_port: Next available port greater than or equal to the requested port. + """ + + avail_port_found = False + try_port = requested_port + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + while not avail_port_found: + try: + sock.bind(("0.0.0.0", try_port)) + avail_port_found = True + except: + try_port += 1 + sock.close() + assigned_port = try_port + + if assigned_port != requested_port: + click.echo( + f"Port {requested_port} was already in use. Using port {assigned_port} instead." + ) + return assigned_port + + +def _graceful_start( + server_name: str, + server_root: str, + pidfile: str, + logfile: str, + port: int, + develop: Optional[bool] = False, +) -> int: + """ + Gracefully start a Flask app with gunicorn. + + Args: + server_name: Name of the server. 'dispatcher' or 'UI'. + server_root: Directory where app.py is located. + pidfile: Process ID file for the server. + logfile: Log file for the server. + port: Port requested to be used by the server. + develop: Start the server in developer mode. + + Returns: + port: Port assigned to the server. + """ + + pid = _read_pid(pidfile) + if psutil.pid_exists(pid): + port = _port_from_pid(pid) + click.echo(f"Covalent {server_name} server is already running at http://0.0.0.0:{port}.") + return port + + _rm_pid_file(pidfile) + + port = _next_available_port(port) + + reload = "--reload" if develop else "" + eventlet = "--worker-class eventlet" if server_name == "UI" else "" + pythonpath = ( + f'--pythonpath="{server_root}/../../tests/functional_tests"' + if develop and server_name == "dispatcher" + else "" + ) + + launch_str = f"gunicorn -w 1 -t 30 -b 0.0.0.0:{port} {eventlet} --daemon --chdir {server_root} --pid {pidfile} --capture-output --log-file {logfile} {reload} {pythonpath} --reuse-port app:app" + + proc = Popen( + launch_str, + shell=True, + ) + + click.echo(f"Covalent {server_name} server has started at http://0.0.0.0:{port}") + + return port + + +def _graceful_shutdown(server_name: str, pidfile: str) -> None: + """ + Gracefully shut down a server given a process ID. + + Args: + server_name: Name of the server. + pidfile: Process ID file for the server. + + Returns: + None + """ + + try: + pid = _read_pid(pidfile) + proc = psutil.Process(pid) + proc.terminate() + proc.wait() + click.echo(f"Covalent {server_name} server has stopped.") + except (psutil.NoSuchProcess, ValueError): + click.echo(f"Covalent {server_name} server was not running.") + + _rm_pid_file(pidfile) + + +def _graceful_restart(server_name: str, pidfile: str) -> bool: + """Gracefully restart a server given a process ID.""" + + pid = _read_pid(pidfile) + if pid != -1: + os.kill(pid, signal.SIGHUP) + click.echo( + f"Covalent {server_name} server has restarted on port http://0.0.0.0:{_port_from_pid(pid)}." + ) + return True + else: + return False + + +@click.command() +@click.option( + "--dispatcher", + is_flag=True, + help="Start only the dispatcher server.", +) +@click.option( + "--ui", + is_flag=True, + help="Start only the UI server.", +) +@click.option( + "-p", + "--port", + default=get_config("dispatcher.port"), + show_default=True, + help="Local dispatcher server port number.", +) +@click.option( + "-P", + "--ui-port", + default=get_config("user_interface.port"), + show_default=True, + help="Local user interface server port number.", +) +@click.option("-d", "--develop", is_flag=True, help="Start the server(s) in developer mode.") +@click.pass_context +def start(ctx, dispatcher: bool, ui: bool, port: int, ui_port: int, develop: bool) -> None: + """ + Start the dispatcher and/or UI servers. + """ + + if not (dispatcher or ui): + dispatcher = True + ui = True + + if dispatcher: + port = _graceful_start( + "dispatcher", DISPATCHER_SRVDIR, DISPATCHER_PIDFILE, DISPATCHER_LOGFILE, port, develop + ) + set_config( + { + "dispatcher.address": "0.0.0.0", + "dispatcher.port": port, + } + ) + + if ui: + ui_port = _graceful_start("UI", UI_SRVDIR, UI_PIDFILE, UI_LOGFILE, ui_port, develop) + set_config( + { + "user_interface.address": "0.0.0.0", + "user_interface.port": ui_port, + } + ) + + +@click.command() +@click.option( + "--dispatcher", + is_flag=True, + help="Stop only the dispatcher server.", +) +@click.option( + "--ui", + is_flag=True, + help="Stop only the UI server.", +) +def stop(dispatcher: bool, ui: bool) -> None: + """ + Stop the dispatcher and/or UI servers. + """ + + if not (dispatcher or ui): + dispatcher = True + ui = True + + if dispatcher: + _graceful_shutdown("dispatcher", DISPATCHER_PIDFILE) + + if ui: + _graceful_shutdown("UI", UI_PIDFILE) + + +@click.command() +@click.option( + "--dispatcher", + is_flag=True, + help="Restart only the dispatcher server.", +) +@click.option( + "--ui", + is_flag=True, + help="Restart only the UI server.", +) +@click.option( + "-p", "--port", default=None, type=int, help="Restart dispatcher server on a different port." +) +@click.option( + "-P", + "--ui-port", + default=None, + type=int, + help="Restart UI server on a different port.", +) +@click.option("-d", "--develop", is_flag=True, help="Start the server(s) in developer mode.") +@click.pass_context +def restart(ctx, dispatcher: bool, ui: bool, port: int, ui_port: int, develop: bool) -> None: + """ + Restart the dispatcher and/or UI servers. + """ + + if not (dispatcher or ui): + dispatcher = True + ui = True + + if dispatcher: + pid = _read_pid(DISPATCHER_PIDFILE) + port = port or _port_from_pid(pid) or get_config("dispatcher.port") + if pid == -1 or port != get_config("dispatcher.port") or develop: + ctx.invoke(stop, dispatcher=True) + ctx.invoke(start, dispatcher=True, port=port, develop=develop) + elif pid != -1: + started = _graceful_restart("dispatcher", DISPATCHER_PIDFILE) + if not started: + ctx.invoke(start, dispatcher=True, port=port, develop=develop) + + if ui: + pid = _read_pid(UI_PIDFILE) + port = ui_port or _port_from_pid(pid) or get_config("user_interface.port") + if pid == -1 or port != get_config("user_interface.port") or develop: + ctx.invoke(stop, ui=True) + ctx.invoke(start, ui=True, ui_port=port, develop=develop) + elif pid != -1: + started = _graceful_restart("user interface", UI_PIDFILE) + if not started: + ctx.invoke(start, ui=True, ui_port=port, develop=develop) + + +@click.command() +def status() -> None: + """ + Query the status of the dispatcher and UI servers. + """ + + dispatcher_port = _port_from_pid(_read_pid(DISPATCHER_PIDFILE)) + if dispatcher_port is not None: + click.echo(f"Covalent dispatcher server is running at http://0.0.0.0:{dispatcher_port}.") + else: + _rm_pid_file(DISPATCHER_PIDFILE) + click.echo("Covalent dispatcher server is stopped.") + + ui_port = _port_from_pid(_read_pid(UI_PIDFILE)) + if ui_port is not None: + click.echo(f"Covalent UI server is running at http://0.0.0.0:{ui_port}.") + else: + _rm_pid_file(UI_PIDFILE) + click.echo("Covalent UI server is stopped.") + + +@click.command() +def purge() -> None: + """ + Delete the cache and config settings. + """ + + shutil.rmtree(get_config("sdk.log_dir"), ignore_errors=True) + shutil.rmtree(get_config("dispatcher.cache_dir"), ignore_errors=True) + shutil.rmtree(get_config("dispatcher.log_dir"), ignore_errors=True) + shutil.rmtree(get_config("user_interface.log_dir"), ignore_errors=True) + + from covalent._shared_files.config import _config_manager as cm + + cm.purge_config() + + click.echo("Covalent server files have been purged.") diff --git a/covalent_dispatcher/_core/__init__.py b/covalent_dispatcher/_core/__init__.py new file mode 100644 index 000000000..01c973f8c --- /dev/null +++ b/covalent_dispatcher/_core/__init__.py @@ -0,0 +1,429 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +""" +Defines the core functionality of the dispatcher +""" + +from datetime import datetime, timezone +from typing import Any, Coroutine, Dict, List + +import cloudpickle as pickle +import dask +from dask.distributed import Client, Variable + +from covalent._results_manager import Result +from covalent._results_manager import results_manager as rm +from covalent._shared_files import logger +from covalent._shared_files.context_managers import active_lattice_manager +from covalent._shared_files.defaults import ( + attr_prefix, + electron_dict_prefix, + electron_list_prefix, + exclude_from_postprocess, + generator_prefix, + parameter_prefix, + sublattice_prefix, + subscript_prefix, +) +from covalent._shared_files.util_classes import TaskExecutionMetadata +from covalent._workflow.lattice import Lattice +from covalent.executor import _executor_manager +from covalent_ui import result_webhook + +app_log = logger.app_log +log_stack_info = logger.log_stack_info + +dask_client = Client(processes=False, dashboard_address=":0") + + +def get_task_inputs(task_input: dict, node_id: int, node_name: str, result_object: Result) -> dict: + """ + Return the required inputs for a task execution. + This makes sure that any node with child nodes isn't executed twice and fetches the + result of parent node to use as input for the child node. + + Args: + task_input: Input dictionary for the task containing the kwargs + assigned to its function. + node_id: Node id of this task in the transport graph. + node_name: Name of the node. + result_object: Result object to be used to update and store execution related + info including the results. + + Returns: + inputs: Input dictionary to be passed to the task containing kwargs + and any parent node execution results if present. + """ + + if node_name.startswith(electron_list_prefix): + values = [ + result_object.lattice.transport_graph.get_node_value(parent, "output") + for parent in result_object.lattice.transport_graph.get_dependencies(node_id) + ] + task_input = {"x": values} + elif node_name.startswith(electron_dict_prefix): + values = {} + for parent in result_object.lattice.transport_graph.get_dependencies(node_id): + key = result_object.lattice.transport_graph.get_edge_value(parent, node_id, "variable") + value = result_object.lattice.transport_graph.get_node_value(parent, "output") + values[key] = value + task_input = {"x": values} + else: + for parent in result_object.lattice.transport_graph.get_dependencies(node_id): + key = result_object.lattice.transport_graph.get_edge_value(parent, node_id, "variable") + value = result_object.lattice.transport_graph.get_node_value(parent, "output") + task_input[key] = value + return task_input + + +def post_process(lattice: Lattice, node_outputs: dict) -> Any: + """ + Post processing function to be called after the lattice execution. + This takes care of executing statements that were not an electron + but were inside the lattice's function. It also replaces any calls + to an electron with the result of that electron execution, hence + preventing a local execution of electron's function. + + Note: Here `node_outputs` is used instead of `electron_outputs` + since an electron can be called multiple times with possibly different + arguments, but every time it's called, it will be executed as a separate node. + Thus, output of every node is used. + + Args: + lattice: Lattice object that was dispatched. + node_outputs: Dictionary containing the output of all the nodes. + + Reurns: + result: The result of the lattice function. + """ + + with active_lattice_manager.claim(lattice): + lattice.post_processing = True + lattice.electron_outputs = node_outputs + result = lattice.workflow_function(**lattice.kwargs) + lattice.post_processing = False + return result + + +def _run_task( + inputs: Dict, + result_object: Result, + node_id: int, +) -> None: + """ + Run a task with given inputs on the selected backend. + Also updates the status of current node execution while + checking if a redispatch has occurred. Exclude those nodes + from execution which were completed. + + Also verifies if execution of this dispatch has been cancelled. + + Args: + inputs: Inputs for the task. + result_object: Result object being used for current dispatch + node_id: Node id of the task to be executed. + + Returns: + None + """ + + serialized_callable = result_object.lattice.transport_graph.get_node_value(node_id, "function") + task_md = result_object.lattice.transport_graph.get_node_value(node_id, "exec_plan") + node_name = ( + result_object.lattice.transport_graph.get_node_value(node_id, "name") + f"({node_id})" + ) + + shared_var = Variable(result_object.dispatch_id, client=dask_client) + if shared_var.get() == str(Result.CANCELLED): + app_log.info("Cancellation requested for dispatch %s", result_object.dispatch_id) + + result_object._update_node( + node_id, + node_name, + None, + None, + Result.CANCELLED, + None, + None, + ) + + result_object.save() + result_webhook.send_update(result_object) + + return + + if result_object._get_node_status(node_id) == Result.COMPLETED: + return + + # the executor is determined during scheduling and provided in the execution metadata + executor = _executor_manager.get_executor(task_md.selected_executor) + + # run the task on the executor and register any failures + try: + start_time = datetime.now(timezone.utc) + result_object._update_node( + node_id, node_name, start_time, None, Result.RUNNING, None, None + ) + result_object.save() + result_webhook.send_update(result_object) + + if node_name.startswith(sublattice_prefix): + func = serialized_callable.get_deserialized() + sublattice_result = func.dispatch_sync(**inputs) + output = sublattice_result.result + + end_time = datetime.now(timezone.utc) + + result_object._update_node( + node_id, + node_name, + start_time, + end_time, + Result.COMPLETED, + output, + None, + sublattice_result, + ) + + else: + output, stdout, stderr = executor.execute( + serialized_callable, + inputs, + task_md.execution_args, + result_object.dispatch_id, + node_id, + ) + + end_time = datetime.now(timezone.utc) + + result_object._update_node( + node_id, + node_name, + start_time, + end_time, + Result.COMPLETED, + output, + None, + stdout=stdout, + stderr=stderr, + ) + + except Exception as ex: + end_time = datetime.now(timezone.utc) + result_object._update_node( + node_id, + node_name, + start_time, + end_time, + Result.FAILED, + None, + ex, + ) + + result_object.save() + result_webhook.send_update(result_object) + + +def _run_planned_workflow(result_object: Result) -> Result: + """ + Run the workflow in the topological order of their position on the + transport graph. Does this in an asynchronous manner so that nodes + at the same level are executed in parallel. Also updates the status + of the whole workflow execution. + + Args: + result_object: Result object being used for current dispatch + + Returns: + None + """ + + shared_var = Variable(result_object.dispatch_id, client=dask_client) + shared_var.set(str(Result.RUNNING)) + + result_object._status = Result.RUNNING + result_object._start_time = datetime.now(timezone.utc) + + order = result_object.lattice.transport_graph.get_topologically_sorted_graph() + + for nodes in order: + tasks: List[Coroutine] = [] + + for node_id in nodes: + # Get all inputs for the current task + task_input = result_object.lattice.transport_graph.get_node_value(node_id, "kwargs") + node_name = result_object.lattice.transport_graph.get_node_value(node_id, "name") + + if node_name.startswith( + (subscript_prefix, generator_prefix, parameter_prefix, attr_prefix) + ): + if node_name.startswith(parameter_prefix): + output = list(task_input.values())[0] + else: + parent = result_object.lattice.transport_graph.get_dependencies(node_id)[0] + output = result_object.lattice.transport_graph.get_node_value(parent, "output") + + if node_name.startswith(attr_prefix): + attr = task_input["attr"] + output = getattr(output, attr) + else: + key = task_input["key"] + output = output[key] + + result_object._update_node( + node_id, + node_name + f"({node_id})", + datetime.now(timezone.utc), + datetime.now(timezone.utc), + Result.COMPLETED, + output, + None, + ) + continue + + task_input = get_task_inputs(task_input, node_id, node_name, result_object) + + # Add the task generated for the node to the list of tasks + tasks.append(dask.delayed(_run_task)(task_input, result_object, node_id)) + + # run the tasks for the current iteration in parallel + dask.compute(*tasks) + + # When one or more nodes failed in the last iteration, don't iterate further + for node_id in nodes: + if result_object._get_node_status(node_id) == Result.FAILED: + result_object._status = Result.FAILED + result_object._end_time = datetime.now(timezone.utc) + result_object._error = f"Node {result_object._get_node_name(node_id)} failed: {result_object._get_node_error(node_id)}" + result_object.save() + result_webhook.send_update(result_object) + return + + elif result_object._get_node_status(node_id) == Result.CANCELLED: + result_object._status = Result.CANCELLED + result_object._end_time = datetime.now(timezone.utc) + result_object.save() + result_webhook.send_update(result_object) + return + + # post process the lattice + node_outputs_for_post_processing = { + k: v + for k, v in result_object.get_all_node_outputs().items() + if all(prefix not in k for prefix in exclude_from_postprocess) + } + result_object._result = post_process(result_object.lattice, node_outputs_for_post_processing) + + result_object._status = Result.COMPLETED + result_object._end_time = datetime.now(timezone.utc) + result_object.save() + result_webhook.send_update(result_object) + + +def _plan_workflow(result_object: Result) -> None: + """ + Plan the workflow for execution, assigning the executor to each node + and assigning some common execution arguments to each node. + + Args: + result_object: Result object being used for current dispatch + + Returns: + None + """ + + serialized_tg = result_object.lattice.transport_graph.serialize(metadata_only=True) + + schedule = result_object.lattice.transport_graph.lattice_metadata.get("schedule", False) + + if schedule: + # Custom scheduling logic + pass + else: + # Default scheduling logic + workflow_schedule = {"nodes": [], "schedule_quality": 1} + deserialized_tg = pickle.loads(serialized_tg) + + # Certain metadata fields are transformed and passed to the executor + for node in deserialized_tg["nodes"]: + workflow_schedule["nodes"].append( + { + "id": node["id"], + "backend": node["metadata"]["backend"][0] + if isinstance(node["metadata"]["backend"], list) + else node["metadata"]["backend"], + # Mutate executor-specific arguments here + "backend_args": {}, + } + ) + + # Attach the execution plan to the transport graph + for node in workflow_schedule["nodes"]: + exec_plan = TaskExecutionMetadata(node["backend"], node["backend_args"]) + result_object._lattice.transport_graph.set_node_value(node["id"], "exec_plan", exec_plan) + + +def run_workflow(dispatch_id: str, results_dir: str) -> None: + """ + Plan and run the workflow by loading the result object corresponding to the + dispatch id and retrieving essential information from it. + Returns without changing anything if a redispatch is done of a (partially or fully) + completed workflow with the same dispatch id. + + Args: + dispatch_id: Dispatch id of the workflow to be run + results_dir: Directory where the result object is stored + + Returns: + None + """ + + result_object = rm._get_result_from_file(dispatch_id, results_dir) + + if result_object.status == Result.COMPLETED: + return + + try: + _plan_workflow(result_object) + _run_planned_workflow(result_object) + + except Exception as ex: + result_object._status = Result.FAILED + result_object._end_time = datetime.now(timezone.utc) + result_object._error = ex + result_object.save() + raise + + +def cancel_workflow(dispatch_id: str) -> None: + """ + Cancels a dispatched workflow using publish subscribe mechanism + provided by Dask. + + Args: + dispatch_id: Dispatch id of the workflow to be cancelled + + Returns: + None + """ + + shared_var = Variable(dispatch_id, client=dask_client) + shared_var.set(str(Result.CANCELLED)) diff --git a/covalent_dispatcher/_service/app.py b/covalent_dispatcher/_service/app.py new file mode 100644 index 000000000..1cc072b5e --- /dev/null +++ b/covalent_dispatcher/_service/app.py @@ -0,0 +1,72 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +import cloudpickle as pickle +from flask import Flask, Response, jsonify, request + +import covalent_dispatcher as dispatcher + +app = Flask(__name__) + + +@app.route("/api/submit", methods=["POST"]) +def submit() -> Response: + """ + Function to accept the submit request of + new dispatch and return the dispatch id + back to the client. + + Args: + None + + Returns: + dispatch_id: The dispatch id in a json format + returned as a Flask Response object. + """ + + data = request.get_data() + result_object = pickle.loads(data) + dispatch_id = dispatcher.run_dispatcher(result_object) + + return jsonify(dispatch_id) + + +@app.route("/api/cancel", methods=["POST"]) +def cancel() -> Response: + """ + Function to accept the cancel request of + a dispatch. + + Args: + None + + Returns: + Flask Response object confirming that the dispatch + has been cancelled. + """ + dispatch_id = request.get_data().decode("utf-8") + + dispatcher.cancel_running_dispatch(dispatch_id) + + return jsonify(f"Dispatch {dispatch_id} cancelled.") + + +if __name__ == "__main__": + app.run() diff --git a/covalent_ui/README.md b/covalent_ui/README.md new file mode 100644 index 000000000..bfcfcd83a --- /dev/null +++ b/covalent_ui/README.md @@ -0,0 +1,32 @@ +# Covalent UI + +## Running UI server + +- Start UI server + +```shell +cd covalent_ui +flask run --port 48008 +``` + +- Open `http://localhost:48008` in your browser. +- Dispatch workflows to explore them in the UI. + +## Setup details + +- Ensure python environment is properly set up with all required packages installed. + +```shell +conda activate +pip install -r requirement.txt +``` + +- The UI server does not require the **Covalent Dispatcher** to be running but it receives execution updates from it. + +- Results are currently persisted in the browser client's `localStorage`. + +## Frontend development + +- The optimized production build of the UI web app lives under `covalent_ui/webapp/build`. It is statically served by the UI server by default. + +- See `covalent_ui/webapp/README.me` for details on how to build and run the development. diff --git a/covalent_ui/__init__.py b/covalent_ui/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/covalent_ui/app.py b/covalent_ui/app.py new file mode 100644 index 000000000..5495bd405 --- /dev/null +++ b/covalent_ui/app.py @@ -0,0 +1,137 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +import os +from datetime import datetime +from logging.handlers import DEFAULT_TCP_LOGGING_PORT + +import networkx as nx +import simplejson +import tailer +from flask import Flask, jsonify, request, send_from_directory +from flask_cors import CORS +from flask_socketio import SocketIO + +from covalent._results_manager import Result +from covalent._results_manager import results_manager as rm +from covalent._shared_files.util_classes import Status + +WEBHOOK_PATH = "/api/webhook" +WEBAPP_PATH = "webapp/build" + +app = Flask(__name__, static_folder=WEBAPP_PATH) +# allow cross-origin requests when API and static files are served separately +CORS(app) +socketio = SocketIO(app, cors_allowed_origins="*") + + +@app.route(WEBHOOK_PATH, methods=["POST"]) +def handle_result_update(): + result_update = request.get_json(force=True) + socketio.emit("result-update", result_update) + return jsonify({"ok": True}) + + +@app.route("/api/results") +def list_results(): + path = request.args["resultsDir"] + dispatch_ids = [dir for dir in os.listdir(path) if os.path.isdir(os.path.join(path, dir))] + return jsonify(dispatch_ids) + + +def encode_result(obj): + if isinstance(obj, Status): + return obj.STATUS + if isinstance(obj, datetime): + return obj.isoformat() + return str(obj) + + +def extract_graph_node(node): + # TODO placeholder for advanced node transformations Eventually, will pick + # instead of omit keys, currently just strip unused fields + f = node.get("function") + if f is not None: + node["doc"] = node["function"].get_deserialized().__doc__ + node.pop("function") + node.pop("node_name") + return node + + +def extract_graph(result): + graph = nx.json_graph.node_link_data(result.lattice.transport_graph._graph) + nodes = list(map(extract_graph_node, graph["nodes"])) + return { + "nodes": nodes, + "links": graph["links"], + } + + +@app.route("/api/results/") +def fetch_result(dispatch_id): + results_dir = request.args["resultsDir"] + + result = rm.get_result(dispatch_id, results_dir=results_dir) + + response = { + "dispatch_id": result.dispatch_id, + "status": result.status, + "result": result.result, + "start_time": result.start_time, + "end_time": result.end_time, + "results_dir": result.results_dir, + "lattice": { + "function_string": result.lattice.workflow_function_string, + "doc": result.lattice.__doc__, + "name": result.lattice.__name__, + "inputs": result.lattice.kwargs, + "metadata": result.lattice.metadata, + }, + "graph": extract_graph(result), + } + + # Use simplejson/ignore_nan=True to handle NaN/Infinity constants + response = simplejson.dumps(response, default=encode_result, ignore_nan=True) + + return app.response_class(response, status=200, mimetype="application/json") + + +@app.route("/api/logoutput") +def fetch_file(): + path = request.args.get("path") + n = int(request.args.get("n", 10)) + lines = tailer.tail(open(path), n) + return jsonify({"lines": lines}) + + +# catch-all: serve web app static files +@app.route("/", defaults={"path": ""}) +@app.route("/") +def serve(path): + if path != "" and os.path.exists(app.static_folder + "/" + path): + # static file + return send_from_directory(app.static_folder, path) + else: + # handle all other routes inside web app + return send_from_directory(app.static_folder, "index.html") + + +if __name__ == "__main__": + socketio.run(app) diff --git a/covalent_ui/result_webhook.py b/covalent_ui/result_webhook.py new file mode 100644 index 000000000..68977828f --- /dev/null +++ b/covalent_ui/result_webhook.py @@ -0,0 +1,67 @@ +# Copyright 2021 Agnostiq Inc. +# +# This file is part of Covalent. +# +# Licensed under the GNU Affero General Public License 3.0 (the "License"). +# A copy of the License may be obtained with this software package or at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# Use of this file is prohibited except in compliance with the License. Any +# modifications or derivative works of this file must retain this copyright +# notice, and modified files must contain a notice indicating that they have +# been altered from the originals. +# +# Covalent is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the License for more details. +# +# Relief from the License may be granted by purchasing a commercial license. + +import json + +import requests + +from covalent._results_manager import Result +from covalent._shared_files import logger +from covalent._shared_files.config import get_config + +from .app import WEBHOOK_PATH + +DEFAULT_PORT = get_config("user_interface.port") + +app_log = logger.app_log + +# UI server webhook for result updates +WEBHOOK_BASE_URL = f"http://localhost:{DEFAULT_PORT}" +WEBHOOK_URL = f"{WEBHOOK_BASE_URL}{WEBHOOK_PATH}" + + +def send_update(result: Result) -> None: + """ + Signal UI server about a result update. Note that the server will expect the + updated result to have been saved to the results directory prior to the + update. + + Args: result: The updated result object. + + Returns: None + """ + + result_update = json.dumps( + { + "event": "change", + "result": { + "dispatch_id": result.dispatch_id, + "results_dir": result.results_dir, + "status": result.status.STATUS, + }, + }, + ) + + try: + # ignore response + requests.post(WEBHOOK_URL, data=result_update) + except requests.exceptions.RequestException: + # catch all requests-related exceptions + app_log.warning("Unable to send result update to UI server.") diff --git a/covalent_ui/webapp/.env.development b/covalent_ui/webapp/.env.development new file mode 100644 index 000000000..300933e68 --- /dev/null +++ b/covalent_ui/webapp/.env.development @@ -0,0 +1,2 @@ +PORT=49009 +REACT_APP_API_URL=http://localhost:47007 diff --git a/covalent_ui/webapp/.env.production b/covalent_ui/webapp/.env.production new file mode 100644 index 000000000..b665b38c0 --- /dev/null +++ b/covalent_ui/webapp/.env.production @@ -0,0 +1 @@ +REACT_APP_API_URL= diff --git a/covalent_ui/webapp/.gitignore b/covalent_ui/webapp/.gitignore new file mode 100644 index 000000000..93f6301d5 --- /dev/null +++ b/covalent_ui/webapp/.gitignore @@ -0,0 +1,26 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# negate parent .gitignore +!**/results/** + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +!build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/covalent_ui/webapp/.prettierrc b/covalent_ui/webapp/.prettierrc new file mode 100644 index 000000000..fd496a820 --- /dev/null +++ b/covalent_ui/webapp/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "semi": false +} diff --git a/covalent_ui/webapp/README.md b/covalent_ui/webapp/README.md new file mode 100644 index 000000000..659dedd60 --- /dev/null +++ b/covalent_ui/webapp/README.md @@ -0,0 +1,32 @@ +# Getting Started + +This project uses [Create React App](https://github.com/facebook/create-react-app). + +See the official Create React App [docs](https://create-react-app.dev/docs/getting-started) to get started. + +## Available Scripts + +In the project directory, you can run: + +### `yarn start` + +Runs the app in the development mode.\ +Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.\ +You will also see any lint errors in the console. + +### `yarn test` + +Launches the test runner in the interactive watch mode.\ +See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `yarn build` + +Builds the app for production to the `build` folder.\ +It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.\ +Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. diff --git a/covalent_ui/webapp/build-demo/asset-manifest.json b/covalent_ui/webapp/build-demo/asset-manifest.json new file mode 100644 index 000000000..f7b93d6b3 --- /dev/null +++ b/covalent_ui/webapp/build-demo/asset-manifest.json @@ -0,0 +1,22 @@ +{ + "files": { + "main.css": "/static/css/main.5658d761.chunk.css", + "main.js": "/static/js/main.deea35c5.chunk.js", + "main.js.map": "/static/js/main.deea35c5.chunk.js.map", + "runtime-main.js": "/static/js/runtime-main.533164ea.js", + "runtime-main.js.map": "/static/js/runtime-main.533164ea.js.map", + "static/js/2.3688fcc7.chunk.js": "/static/js/2.3688fcc7.chunk.js", + "static/js/2.3688fcc7.chunk.js.map": "/static/js/2.3688fcc7.chunk.js.map", + "index.html": "/index.html", + "static/css/main.5658d761.chunk.css.map": "/static/css/main.5658d761.chunk.css.map", + "static/js/2.3688fcc7.chunk.js.LICENSE.txt": "/static/js/2.3688fcc7.chunk.js.LICENSE.txt", + "static/media/atom.620f45ef.svg": "/static/media/atom.620f45ef.svg", + "static/media/covalent-full-logo.c0b996e7.svg": "/static/media/covalent-full-logo.c0b996e7.svg" + }, + "entrypoints": [ + "static/js/runtime-main.533164ea.js", + "static/js/2.3688fcc7.chunk.js", + "static/css/main.5658d761.chunk.css", + "static/js/main.deea35c5.chunk.js" + ] +} diff --git a/covalent_ui/webapp/build-demo/index.html b/covalent_ui/webapp/build-demo/index.html new file mode 100644 index 000000000..a687b5ff9 --- /dev/null +++ b/covalent_ui/webapp/build-demo/index.html @@ -0,0 +1 @@ +Covalent Dashboard
diff --git a/covalent_ui/webapp/build-demo/logo192.png b/covalent_ui/webapp/build-demo/logo192.png new file mode 100644 index 0000000000000000000000000000000000000000..359e2841411cab848b15a67fc288835be85e9917 GIT binary patch literal 6781 zcmV-@8iM7CP){fEi#|2gEM13Cu3B7zwm*Mt)i>Tf}l?D{8SCwW<3630(* zV#l(gD3UGd$w)F-5(t4TkU(r^)36B`hGp1hXZGpoTlM~^CP4xu4BfZ8@2%hGGaq1p zhFkaiPMve=)b9u`5s~>N01_w$t^&pZVRl?RqZ8x zh`2<<4*})CLf{tQYM^KA`_}L+l1+qYj0_(ED}gtF-9Xo85kY*0@e80Y@F4IIFcb*e zHMdA%M1d2)tH4vhf$*wY^*a$D=JmtCT;RLFG$6yStwkC^0egUd0$u@HFSHwoix_`4 z@RgYH_q&u($-*K8d_%q|oY1H2oS5Ij!jH%Yz6DJ9 zWC#?BZ4uLL!fWAk32t7&>#idZ#6H#0OMZF-e5RqE|p$rITU6=roE{JrZ z+nV7_1G>2$8fwu^b4cd^}>%2t=>GkXryw=zNbJFGvZQ*^rryC@6-$gAq&tokQ9kkto;X5mkFoTi2kszlT0v1)XhiF(6Ss8u`GVm~hW4j#ur)ec_*= zz14<5aSd@YGZFoUA|}m2PQ4K^cogL3nRq{4Asr|#K@?w)Gj0aDZZUe#X7q-)P!$`Y zsTN%K@;|?z2swThBxd&w9sz`a>^#Kqamed#Lrk2FDD9V;;msBAY#~JN z{^t3n+<>gwjas)Hy?GV-#9@;>+ax$ZhM!l6xMmu1-aW{%)1jb;x3O$8pFJlJF=h(R zh>7Th_oLP?N5A)L^sxh`3~LGC=a-*v41fM2vwi0k2E*_#mgEl{j?-@l`nuat>)t@G zUV=V;2%_DV0KP&v3o(2=^5zGTljcD|ac~X)Lg7)rAvpJZ9X(|}>YZ26YnP#GssmL< z4f*!v_8*E|a6jVu+YvqcSi}FcwHiDM=S$y4&$tQo>t|7$RzYi1AP(33MF1fnzZf~= zCgg1oBLxV&9_E< zImj(QUVjH-#01pq&!T?wnkk+7bT{w;0febdUw;Sku164M<>_6=PX$PcC@aVL@}D8b zPDd^I33}gFU+xB>w0}_ph9U2H6glfw$gy5OuE@+nPQ3v!a5(CfpP<$*!*7=d)0Y4l zVZ^wZI1l_OV#IhG>nCi3m8M#>_r4zgq(jb^6uY9lvpWKPmouL zyy-!7!)eIMu>?qtHxh`ReUM*x40*#BZKCVBwPYYl{Usb8N-N{q_GJr;KoG!j5ThpHeC@9g!^WALQWh40Ab{hTO3zonj~Ft> zwli1+hyad*m^d5fk-tC;9Bz%@A~Df*%EtUxPsMrU`_}j^0!9EK5hEtxEPetpaD+8} zivSTo2t@fP6Z4OlXpP?@SOgHI{gGe(4r26VYy1`gBS1kha?xYRNpp>|frW(!NR28` zRu1ykuOR0y@{c-$*8eSd>$(t)7!?MkVrmRArcVyYV%`rJ+z)dcXb+tv#w4ftec%@`fGCXAg{>i`Sk3A z=-nTB_B8^#S-FrAwjrS}2_OVw$Y|sjzX`=9>F4325p+{M96NwMSb?srFp`9gwMOYV z+6~dD*#$oBqt5=saZFoxI15qG1A6sA3?79THWpDn8qsG^Oq0}xi2fizaVhe?KSq?N z(R}XiE_D5A^!^>_9q*&}ZAYIvYE+t)du5;Py5{TbPI96O{ow|)0~GW?3>;?UUB=BY zCF1--n=hp;0m50xh4&*T&rAK7S8M2KMIYLO+O!J2eXa5I9qpg#-Qz>L$bW@Z`oj&V zH~tfG)mU>|Yr-r<=>S6#i!>pC5XO_;^d+PFn97FV){Ne>8MS69ddE6+V{LLJ1>Gn# z)Sx%7#@)Hzw1`hzfS7eFqW@4!gmfT)=-C%%(PKtuKZQNM+O-+I@trt)mR;Gs} zh#N&8JAhvDWAw(A$OZQsk$|4PZAmqy2p|Mv*jVI(`%-VK)*71XQ18Bmdhseh$O zZ8FGPwHNo4qa@-6vw#gy|2#{BVynQjE&%o3(oPFC+ulyTo+Zr=wD4o&S zj^6SPZsjiY!uyd6A24&w>{&t*2_PhL(wx+*`n0v6*1eAU<&V+FEBzx3t2NZ0LM{0* zx^lP4xkgU3@-ayxKyeB3rUxOfAa$O;?j-Kgr%@|kf;090e8XLx=uL0qo;r$r;7^cK z=9_V?79J8nI>;Fd5u>gpC6vXqMpsv&p8p5bh86xF5TO*hY7g#D9*3H0dD?n!vMo7f9vk~Q^lJEJC?#F%RudVT)Ljv{sv$(JR)HL#0 z0we(WMab)JPkO(PuBk>n|BvXM>#gyBj07#HH~tf~>Sc3J!4e>z-d`X_PcqWwNsW0M zQUC9sQ5#pKE65z@|)iKF$ zNm=sV>8T^QFaHRA`j|EFOLZ8(eHXRj1?cLq1h}%~w-9;l?Bw;NcXgna{{p>dOW?Nj zD?+3T_0|jMT^qf*>E>4gh=Ie6nsc(Y^NNkAcb3?=|8kbE_5|*-|3Ej?S^`|&CrZTl zSx``%oF{6k#r^d&fs1A1#{gw6`@gp=5LKc06Ck$$Id)od)Cyb|wefBAhacF`=StAo zj#~K=`b3o_!0#OX^c{>CFg!WVtL_Bq?U!xUCmw5gbU*6-H;kg4CBUUxzeEfl2Zc%K zEm1Cd<4W|w53Tja1JQ2u+NJ2~LzV!SjEt~Rc22^rBi&GgTC*%rCA@^MX>}!P{c>OL z0&yjPDD07(>W^0FiVf&PyR6m56WtN?h85`A6P5s%gtGGFOm1&$LBIb7bhKHcjkj+( zvLC%;oo~+t;zs}>5Q9fTc5V`0(mwRQt=3u-fk-EMk?>Z8+6*< ze~%deEe&=DxKI*|-`?du5 zICP{7+C1*d35B7wzcorv!_FK;&psq=>{ZI{09~EXdd6b{gb;lPCr5@os1ZK z)icG10Fh2~Q=P|eLm>JM@%|!ykWo^GDC%hma2}L0ed3;;1qkRn2$2ja_CUISffz6h zatbT~E|3MFPapNX6e@~Kq3>X8oF3&|V(8VrJAIE20klS+I_7N5WRckT zfAnPVTKOZbc7XO)qtoN{yD9FCxMqqCgA$3nLgcuarUB6s;3DYmLLc7ey-sIF7&-nr z?`2tnv;hnnVMbs1s0S$i1W*d9_If|0P6!x2&J5?Uh(AIZh{u}aS)T{*km~F*5M!~&PMdV%D;~o z*H7!}K<)i)QiPL4Svg|*0((m=o@?5pH*)qJM)t-M;8OAc*Gy|{Yw`X`GQ!B&clxqc zogC|zh$){(3>)Xm} z*rH@emV`5rbMHo!kG2+kMLAUnG3yq@u(7`O{)r(#v>UZ;P0|Keh_Z6z&0n(DC9h-+ z%SRy>-0$nyKXC*A^ub-|>O)ELUJi2lO~^@e?dkC4Ag>U4%a;)Yt_sBCCdNV6QOutZ&!yzYxoIDTb;U|pLNr2ZP@tI+y3$Nfj1E?HC^H*5_ikhS{f642fL8>dy9>2?3A*}V%6LIBX)ew;e}I@YCm7wMg*|ZY z`8v+x@0k;FYy2J(0MN$|p;rGgbtXGXX{tlt_&emn2mE`fUP{D(VK@&zfn4+rC@!&9 zp9})vM$v1QqCeV}I!`YoqHHkEL*K!9_;J$!=BEa_a3Zea zAJetRQOlme88kAr`c3kSkP9C`Ts0Q8?B7wFR(U_~Al_cT_dw)=`;a$$5qk8tAx|n0 z0Hsh{*C0Mvj=bT2q?Wf0WgtdQ#Oe1pi19N~Z~h#8Xt$YulP(Yfato24n}@vlA;gFY zW}K`=iVy&xtp&C08N}$xh=IdX&wvVgAm`tUxOysj?NZdczd|2Bl>Bpy&q7W)=+ajbVrb5r$a^xdMGIo1w9N&CtQap>;)}N=CXe( z5kW|!+B|*+&V7H3y!%n)$O({{<1gc{sYb0?3Xx79>;M3+i(2;vV)SHl@j6u}kB2gh zEMQqVV)h;AE$^T~XrBOl?u^dzA_{0AsbgOR6>1I4B05N-TSXsS1--21kn_wPVgSE3th&B)kj z_vH(ONyi+{)X`oDM~ zAtWJ`2ibX8GfrKk%$}-`SK&VQ_vpiWlcOqUVF{321}OBtZK&t|5Bl^m`(`WxMu1pS ztTw-6NKkjez8#Bz5de&+*88ucUihJ@o>*7}iU44)QNHsE>ZK5kMf6Bfsi+~Z}ED2VQAAg%@QE#Xl_9L>S^46{Vsa{j?_?{ z^DEj~P%B@=eezqVo$EpQXRXtF5LBcS^}!1C@k->Kk07tR&0H3-h|_MX(8sG#zxo;K z-PfS?45CM=uO2b|C!r}9U9}hYsqdqAZ$aMqRm7l?se8{jUC_~r+O!Jw+EeHQANscF z;Ga=|ZOy3FzeFF{iM;hI$XT~Sev!RYayha7(fz15opB?A7 zq4#b@t@s6M`+LyR7`T$M|1BXF)4DJI5b@rxk+bha%)HqsE`$O~g!UG5`)>6T)V8(I zSR2^(lHgcCcLZIv2lvb zh!{K<80|Ju#a*DN&(Ytt4W$4rL8o<18CtsxRYpFE7-widO1Il8g}+FR}Ed0+`} zZfI0fjb6P3K3IV&ABC7S2RY$-lQ8Gxr*8?>jiMWC(EE3yH@%In*odyFj?Z)+r6C$I z+D0BatwcdY=9g>)rdVHqIXo-qi5M~(Ic^5xnrTLVGq*6c^98LT(ur=UL09cYZ+#EF zXEXZ5Vd!j&ueUGig}i#Ir*qYGQyqHO#)Od065yhHV+Q0EAqEUZjF^ZRInfCD_UvN> zX_KkkrnT{kEsf~Y$Iu5W(7U&wD=W}7$DzxMj!iG0J#pchtp|SEw%b&TZmLD^-VB-9 zh@xK5cQB%S6ry~L8Mxi643S@GWDXN?&Y-mkT{_#)XX@e9Q6s`zS%E%!z=Srf%_c1I zG_LnY4q)D9Uz$@NOL2)xe<;ZLL)#5kRfnn zO!PJv5zaD(AIgZu&Eh-)(A{a;4kDfCt`2kQ#EqI3Z{^yGjU_-@u)Z@0Y#kzDgb+-)*^_gl)!I+HoF!U0Yem6CxP8S zm0b^ufT7_m0Zsy|0IN4>5hQE|cAu>REd{LnvPDqP4!jC9$?&RLfbGDW*lLhPFt7!9 z3(#i|!a9JT0F`!aEPRee;7QQBS7poP6Lm} zNYHNA&cX*_&uZWsz@G4`+K&}_E_kmkGQR|%C-7C^F`%DaM~gJX8Q_Ij*mLBQ#(z-) zoI`>PU@Gt}U@nl4?*()$e1HyME2gNk0%$uo?71WYoI?VDVqgxi2$%_!VlLBIGFYSv zTug~`EAR^DT|)800000NkvXXu0mjfoQ3`Q literal 0 HcmV?d00001 diff --git a/covalent_ui/webapp/build-demo/manifest.json b/covalent_ui/webapp/build-demo/manifest.json new file mode 100644 index 000000000..7fe01e341 --- /dev/null +++ b/covalent_ui/webapp/build-demo/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "Covalent Dashboard", + "name": "Covalent Dashboard", + "icons": [ + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/covalent_ui/webapp/build-demo/robots.txt b/covalent_ui/webapp/build-demo/robots.txt new file mode 100644 index 000000000..e9e57dc4d --- /dev/null +++ b/covalent_ui/webapp/build-demo/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/covalent_ui/webapp/build-demo/static/css/main.5658d761.chunk.css b/covalent_ui/webapp/build-demo/static/css/main.5658d761.chunk.css new file mode 100644 index 000000000..b724b78ef --- /dev/null +++ b/covalent_ui/webapp/build-demo/static/css/main.5658d761.chunk.css @@ -0,0 +1,2 @@ +.spin-electron{-webkit-animation:spin-icon 2s linear infinite;animation:spin-icon 2s linear infinite}@-webkit-keyframes spin-icon{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes spin-icon{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.react-flow__handle{visibility:hidden}.react-flow__handle-bottom{bottom:0!important}.react-flow__handle-top{top:0!important}.react-flow__handle-left{left:0!important}.react-flow__handle-right{right:0!important} +/*# sourceMappingURL=main.5658d761.chunk.css.map */ diff --git a/covalent_ui/webapp/build-demo/static/css/main.5658d761.chunk.css.map b/covalent_ui/webapp/build-demo/static/css/main.5658d761.chunk.css.map new file mode 100644 index 000000000..1fc471e0d --- /dev/null +++ b/covalent_ui/webapp/build-demo/static/css/main.5658d761.chunk.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack://src/App.css"],"names":[],"mappings":"AAsBA,eACE,8CAAuC,CAAvC,sCACF,CAEA,6BACE,GACE,8BAAuB,CAAvB,sBACF,CACA,GACE,+BAAyB,CAAzB,uBACF,CACF,CAPA,qBACE,GACE,8BAAuB,CAAvB,sBACF,CACA,GACE,+BAAyB,CAAzB,uBACF,CACF,CAGA,oBACE,iBACF,CACA,2BACE,kBACF,CACA,wBACE,eACF,CACA,yBACE,gBACF,CACA,0BACE,iBACF","file":"main.5658d761.chunk.css","sourcesContent":["/**\n * Copyright 2021 Agnostiq Inc.\n *\n * This file is part of Covalent.\n *\n * Licensed under the GNU Affero General Public License 3.0 (the \"License\").\n * A copy of the License may be obtained with this software package or at\n *\n * https://www.gnu.org/licenses/agpl-3.0.en.html\n *\n * Use of this file is prohibited except in compliance with the License. Any\n * modifications or derivative works of this file must retain this copyright\n * notice, and modified files must contain a notice indicating that they have\n * been altered from the originals.\n *\n * Covalent is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE. See the License for more details.\n *\n * Relief from the License may be granted by purchasing a commercial license.\n */\n\n.spin-electron {\n animation: spin-icon infinite 2s linear;\n}\n\n@keyframes spin-icon {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* TODO quick hack to disable handles */\n.react-flow__handle {\n visibility: hidden;\n}\n.react-flow__handle-bottom {\n bottom: 0px !important;\n}\n.react-flow__handle-top {\n top: 0px !important;\n}\n.react-flow__handle-left {\n left: 0px !important;\n}\n.react-flow__handle-right {\n right: 0px !important;\n}\n"]} diff --git a/covalent_ui/webapp/build-demo/static/js/2.3688fcc7.chunk.js b/covalent_ui/webapp/build-demo/static/js/2.3688fcc7.chunk.js new file mode 100644 index 000000000..f20303b9c --- /dev/null +++ b/covalent_ui/webapp/build-demo/static/js/2.3688fcc7.chunk.js @@ -0,0 +1,3 @@ +/*! For license information please see 2.3688fcc7.chunk.js.LICENSE.txt */ +(this.webpackJsonpwebapp=this.webpackJsonpwebapp||[]).push([[2],[function(e,t,n){"use strict";e.exports=n(301)},function(e,t,n){"use strict";e.exports=n(330)},function(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;t=0||(o[n]=e[n]);return o}n.d(t,"a",(function(){return r}))},function(e,t,n){"use strict";n.d(t,"b",(function(){return x})),n.d(t,"c",(function(){return E}));var r=n(22),o=n(2),i=n(4),a=n(112),c=n(554),u=n(546),s=n(285),l=["variant"];function f(e){return 0===e.length}function d(e){var t=e.variant,n=Object(i.a)(e,l),r=t||"";return Object.keys(n).sort().forEach((function(t){r+="color"===t?f(r)?e[t]:Object(s.a)(e[t]):"".concat(f(r)?t:Object(s.a)(t)).concat(Object(s.a)(e[t].toString()))})),r}var p=["name","slot","skipVariantsResolver","skipSx","overridesResolver"],h=["theme"],v=["theme"];function m(e){return 0===Object.keys(e).length}var g=function(e,t){return t.components&&t.components[e]&&t.components[e].styleOverrides?t.components[e].styleOverrides:null},b=function(e,t){var n=[];t&&t.components&&t.components[e]&&t.components[e].variants&&(n=t.components[e].variants);var r={};return n.forEach((function(e){var t=d(e.props);r[t]=e.style})),r},y=function(e,t,n,r){var o,i,a=e.ownerState,c=void 0===a?{}:a,u=[],s=null==n||null==(o=n.components)||null==(i=o[r])?void 0:i.variants;return s&&s.forEach((function(n){var r=!0;Object.keys(n.props).forEach((function(t){c[t]!==n.props[t]&&e[t]!==n.props[t]&&(r=!1)})),r&&u.push(t[d(n.props)])})),u};function w(e){return"ownerState"!==e&&"theme"!==e&&"sx"!==e&&"as"!==e}var O=Object(c.a)();var j=n(73),x=function(e){return w(e)&&"classes"!==e},E=w,_=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.defaultTheme,n=void 0===t?O:t,c=e.rootShouldForwardProp,s=void 0===c?w:c,l=e.slotShouldForwardProp,f=void 0===l?w:l;return function(e){var t,c=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},l=c.name,d=c.slot,O=c.skipVariantsResolver,j=c.skipSx,x=c.overridesResolver,E=Object(i.a)(c,p),_=void 0!==O?O:d&&"Root"!==d||!1,k=j||!1;var S=w;"Root"===d?S=s:d&&(S=f);var C=Object(a.a)(e,Object(o.a)({shouldForwardProp:S,label:t},E)),P=function(e){for(var t=arguments.length,a=new Array(t>1?t-1:0),c=1;c0){var p=new Array(d).fill("");(f=[].concat(Object(r.a)(e),Object(r.a)(p))).raw=[].concat(Object(r.a)(e.raw),Object(r.a)(p))}else"function"===typeof e&&(f=function(t){var r=t.theme,a=Object(i.a)(t,v);return e(Object(o.a)({theme:m(r)?n:r},a))});var w=C.apply(void 0,[f].concat(Object(r.a)(s)));return w};return P}}({defaultTheme:j.a,rootShouldForwardProp:x});t.a=_},function(e,t,n){"use strict";function r(e){var t,n,o="";if("string"===typeof e||"number"===typeof e)o+=e;else if("object"===typeof e)if(Array.isArray(e))for(t=0;t3&&void 0!==arguments[3]?arguments[3]:n;return r="function"===typeof e?e(n):Array.isArray(e)?e[n]||o:a(e,n)||o,t&&(r=t(r)),r}t.a=function(e){var t=e.prop,n=e.cssProperty,u=void 0===n?e.prop:n,s=e.themeKey,l=e.transform,f=function(e){if(null==e[t])return null;var n=e[t],f=a(e.theme,s)||{};return Object(i.b)(e,n,(function(e){var n=c(f,l,e);return e===n&&"string"===typeof e&&(n=c(f,l,"".concat(t).concat("default"===e?"":Object(o.a)(e)),e)),!1===u?n:Object(r.a)({},u,n)}))};return f.propTypes={},f.filterProps=[t],f}},function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));var r=n(261);var o=n(95),i=n(262);function a(e,t){return Object(r.a)(e)||function(e,t){if("undefined"!==typeof Symbol&&Symbol.iterator in Object(e)){var n=[],r=!0,o=!1,i=void 0;try{for(var a,c=e[Symbol.iterator]();!(r=(a=c.next()).done)&&(n.push(a.value),!t||n.length!==t);r=!0);}catch(u){o=!0,i=u}finally{try{r||null==c.return||c.return()}finally{if(o)throw i}}return n}}(e,t)||Object(o.a)(e,t)||Object(i.a)()}},function(e,t,n){(function(e,r){var o;(function(){var i,a="Expected a function",c="__lodash_hash_undefined__",u="__lodash_placeholder__",s=16,l=32,f=64,d=128,p=256,h=1/0,v=9007199254740991,m=NaN,g=4294967295,b=[["ary",d],["bind",1],["bindKey",2],["curry",8],["curryRight",s],["flip",512],["partial",l],["partialRight",f],["rearg",p]],y="[object Arguments]",w="[object Array]",O="[object Boolean]",j="[object Date]",x="[object Error]",E="[object Function]",_="[object GeneratorFunction]",k="[object Map]",S="[object Number]",C="[object Object]",P="[object Promise]",M="[object RegExp]",T="[object Set]",N="[object String]",R="[object Symbol]",A="[object WeakMap]",L="[object ArrayBuffer]",I="[object DataView]",D="[object Float32Array]",z="[object Float64Array]",B="[object Int8Array]",F="[object Int16Array]",U="[object Int32Array]",W="[object Uint8Array]",H="[object Uint8ClampedArray]",V="[object Uint16Array]",$="[object Uint32Array]",Y=/\b__p \+= '';/g,q=/\b(__p \+=) '' \+/g,X=/(__e\(.*?\)|\b__t\)) \+\n'';/g,K=/&(?:amp|lt|gt|quot|#39);/g,G=/[&<>"']/g,Q=RegExp(K.source),Z=RegExp(G.source),J=/<%-([\s\S]+?)%>/g,ee=/<%([\s\S]+?)%>/g,te=/<%=([\s\S]+?)%>/g,ne=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,re=/^\w*$/,oe=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,ie=/[\\^$.*+?()[\]{}|]/g,ae=RegExp(ie.source),ce=/^\s+/,ue=/\s/,se=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,le=/\{\n\/\* \[wrapped with (.+)\] \*/,fe=/,? & /,de=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,pe=/[()=,{}\[\]\/\s]/,he=/\\(\\)?/g,ve=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,me=/\w*$/,ge=/^[-+]0x[0-9a-f]+$/i,be=/^0b[01]+$/i,ye=/^\[object .+?Constructor\]$/,we=/^0o[0-7]+$/i,Oe=/^(?:0|[1-9]\d*)$/,je=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,xe=/($^)/,Ee=/['\n\r\u2028\u2029\\]/g,_e="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",ke="\\u2700-\\u27bf",Se="a-z\\xdf-\\xf6\\xf8-\\xff",Ce="A-Z\\xc0-\\xd6\\xd8-\\xde",Pe="\\ufe0e\\ufe0f",Me="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Te="['\u2019]",Ne="[\\ud800-\\udfff]",Re="["+Me+"]",Ae="["+_e+"]",Le="\\d+",Ie="[\\u2700-\\u27bf]",De="["+Se+"]",ze="[^\\ud800-\\udfff"+Me+Le+ke+Se+Ce+"]",Be="\\ud83c[\\udffb-\\udfff]",Fe="[^\\ud800-\\udfff]",Ue="(?:\\ud83c[\\udde6-\\uddff]){2}",We="[\\ud800-\\udbff][\\udc00-\\udfff]",He="["+Ce+"]",Ve="(?:"+De+"|"+ze+")",$e="(?:"+He+"|"+ze+")",Ye="(?:['\u2019](?:d|ll|m|re|s|t|ve))?",qe="(?:['\u2019](?:D|LL|M|RE|S|T|VE))?",Xe="(?:"+Ae+"|"+Be+")"+"?",Ke="[\\ufe0e\\ufe0f]?",Ge=Ke+Xe+("(?:\\u200d(?:"+[Fe,Ue,We].join("|")+")"+Ke+Xe+")*"),Qe="(?:"+[Ie,Ue,We].join("|")+")"+Ge,Ze="(?:"+[Fe+Ae+"?",Ae,Ue,We,Ne].join("|")+")",Je=RegExp(Te,"g"),et=RegExp(Ae,"g"),tt=RegExp(Be+"(?="+Be+")|"+Ze+Ge,"g"),nt=RegExp([He+"?"+De+"+"+Ye+"(?="+[Re,He,"$"].join("|")+")",$e+"+"+qe+"(?="+[Re,He+Ve,"$"].join("|")+")",He+"?"+Ve+"+"+Ye,He+"+"+qe,"\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",Le,Qe].join("|"),"g"),rt=RegExp("[\\u200d\\ud800-\\udfff"+_e+Pe+"]"),ot=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,it=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],at=-1,ct={};ct[D]=ct[z]=ct[B]=ct[F]=ct[U]=ct[W]=ct[H]=ct[V]=ct[$]=!0,ct[y]=ct[w]=ct[L]=ct[O]=ct[I]=ct[j]=ct[x]=ct[E]=ct[k]=ct[S]=ct[C]=ct[M]=ct[T]=ct[N]=ct[A]=!1;var ut={};ut[y]=ut[w]=ut[L]=ut[I]=ut[O]=ut[j]=ut[D]=ut[z]=ut[B]=ut[F]=ut[U]=ut[k]=ut[S]=ut[C]=ut[M]=ut[T]=ut[N]=ut[R]=ut[W]=ut[H]=ut[V]=ut[$]=!0,ut[x]=ut[E]=ut[A]=!1;var st={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},lt=parseFloat,ft=parseInt,dt="object"==typeof e&&e&&e.Object===Object&&e,pt="object"==typeof self&&self&&self.Object===Object&&self,ht=dt||pt||Function("return this")(),vt=t&&!t.nodeType&&t,mt=vt&&"object"==typeof r&&r&&!r.nodeType&&r,gt=mt&&mt.exports===vt,bt=gt&&dt.process,yt=function(){try{var e=mt&&mt.require&&mt.require("util").types;return e||bt&&bt.binding&&bt.binding("util")}catch(t){}}(),wt=yt&&yt.isArrayBuffer,Ot=yt&&yt.isDate,jt=yt&&yt.isMap,xt=yt&&yt.isRegExp,Et=yt&&yt.isSet,_t=yt&&yt.isTypedArray;function kt(e,t,n){switch(n.length){case 0:return e.call(t);case 1:return e.call(t,n[0]);case 2:return e.call(t,n[0],n[1]);case 3:return e.call(t,n[0],n[1],n[2])}return e.apply(t,n)}function St(e,t,n,r){for(var o=-1,i=null==e?0:e.length;++o-1}function Rt(e,t,n){for(var r=-1,o=null==e?0:e.length;++r-1;);return n}function nn(e,t){for(var n=e.length;n--&&Wt(t,e[n],0)>-1;);return n}function rn(e,t){for(var n=e.length,r=0;n--;)e[n]===t&&++r;return r}var on=qt({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),an=qt({"&":"&","<":"<",">":">",'"':""","'":"'"});function cn(e){return"\\"+st[e]}function un(e){return rt.test(e)}function sn(e){var t=-1,n=Array(e.size);return e.forEach((function(e,r){n[++t]=[r,e]})),n}function ln(e,t){return function(n){return e(t(n))}}function fn(e,t){for(var n=-1,r=e.length,o=0,i=[];++n",""":'"',"'":"'"});var bn=function e(t){var n=(t=null==t?ht:bn.defaults(ht.Object(),t,bn.pick(ht,it))).Array,r=t.Date,o=t.Error,ue=t.Function,_e=t.Math,ke=t.Object,Se=t.RegExp,Ce=t.String,Pe=t.TypeError,Me=n.prototype,Te=ue.prototype,Ne=ke.prototype,Re=t["__core-js_shared__"],Ae=Te.toString,Le=Ne.hasOwnProperty,Ie=0,De=function(){var e=/[^.]+$/.exec(Re&&Re.keys&&Re.keys.IE_PROTO||"");return e?"Symbol(src)_1."+e:""}(),ze=Ne.toString,Be=Ae.call(ke),Fe=ht._,Ue=Se("^"+Ae.call(Le).replace(ie,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),We=gt?t.Buffer:i,He=t.Symbol,Ve=t.Uint8Array,$e=We?We.allocUnsafe:i,Ye=ln(ke.getPrototypeOf,ke),qe=ke.create,Xe=Ne.propertyIsEnumerable,Ke=Me.splice,Ge=He?He.isConcatSpreadable:i,Qe=He?He.iterator:i,Ze=He?He.toStringTag:i,tt=function(){try{var e=pi(ke,"defineProperty");return e({},"",{}),e}catch(t){}}(),rt=t.clearTimeout!==ht.clearTimeout&&t.clearTimeout,st=r&&r.now!==ht.Date.now&&r.now,dt=t.setTimeout!==ht.setTimeout&&t.setTimeout,pt=_e.ceil,vt=_e.floor,mt=ke.getOwnPropertySymbols,bt=We?We.isBuffer:i,yt=t.isFinite,Bt=Me.join,qt=ln(ke.keys,ke),yn=_e.max,wn=_e.min,On=r.now,jn=t.parseInt,xn=_e.random,En=Me.reverse,_n=pi(t,"DataView"),kn=pi(t,"Map"),Sn=pi(t,"Promise"),Cn=pi(t,"Set"),Pn=pi(t,"WeakMap"),Mn=pi(ke,"create"),Tn=Pn&&new Pn,Nn={},Rn=Fi(_n),An=Fi(kn),Ln=Fi(Sn),In=Fi(Cn),Dn=Fi(Pn),zn=He?He.prototype:i,Bn=zn?zn.valueOf:i,Fn=zn?zn.toString:i;function Un(e){if(rc(e)&&!Ya(e)&&!(e instanceof $n)){if(e instanceof Vn)return e;if(Le.call(e,"__wrapped__"))return Ui(e)}return new Vn(e)}var Wn=function(){function e(){}return function(t){if(!nc(t))return{};if(qe)return qe(t);e.prototype=t;var n=new e;return e.prototype=i,n}}();function Hn(){}function Vn(e,t){this.__wrapped__=e,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=i}function $n(e){this.__wrapped__=e,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=g,this.__views__=[]}function Yn(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t=t?e:t)),e}function sr(e,t,n,r,o,a){var c,u=1&t,s=2&t,l=4&t;if(n&&(c=o?n(e,r,o,a):n(e)),c!==i)return c;if(!nc(e))return e;var f=Ya(e);if(f){if(c=function(e){var t=e.length,n=new e.constructor(t);t&&"string"==typeof e[0]&&Le.call(e,"index")&&(n.index=e.index,n.input=e.input);return n}(e),!u)return To(e,c)}else{var d=mi(e),p=d==E||d==_;if(Ga(e))return _o(e,u);if(d==C||d==y||p&&!o){if(c=s||p?{}:bi(e),!u)return s?function(e,t){return No(e,vi(e),t)}(e,function(e,t){return e&&No(t,Ac(t),e)}(c,e)):function(e,t){return No(e,hi(e),t)}(e,ir(c,e))}else{if(!ut[d])return o?e:{};c=function(e,t,n){var r=e.constructor;switch(t){case L:return ko(e);case O:case j:return new r(+e);case I:return function(e,t){var n=t?ko(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.byteLength)}(e,n);case D:case z:case B:case F:case U:case W:case H:case V:case $:return So(e,n);case k:return new r;case S:case N:return new r(e);case M:return function(e){var t=new e.constructor(e.source,me.exec(e));return t.lastIndex=e.lastIndex,t}(e);case T:return new r;case R:return o=e,Bn?ke(Bn.call(o)):{}}var o}(e,d,u)}}a||(a=new Gn);var h=a.get(e);if(h)return h;a.set(e,c),uc(e)?e.forEach((function(r){c.add(sr(r,t,n,r,e,a))})):oc(e)&&e.forEach((function(r,o){c.set(o,sr(r,t,n,o,e,a))}));var v=f?i:(l?s?ai:ii:s?Ac:Rc)(e);return Ct(v||e,(function(r,o){v&&(r=e[o=r]),nr(c,o,sr(r,t,n,o,e,a))})),c}function lr(e,t,n){var r=n.length;if(null==e)return!r;for(e=ke(e);r--;){var o=n[r],a=t[o],c=e[o];if(c===i&&!(o in e)||!a(c))return!1}return!0}function fr(e,t,n){if("function"!=typeof e)throw new Pe(a);return Ri((function(){e.apply(i,n)}),t)}function dr(e,t,n,r){var o=-1,i=Nt,a=!0,c=e.length,u=[],s=t.length;if(!c)return u;n&&(t=At(t,Zt(n))),r?(i=Rt,a=!1):t.length>=200&&(i=en,a=!1,t=new Kn(t));e:for(;++o-1},qn.prototype.set=function(e,t){var n=this.__data__,r=rr(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this},Xn.prototype.clear=function(){this.size=0,this.__data__={hash:new Yn,map:new(kn||qn),string:new Yn}},Xn.prototype.delete=function(e){var t=fi(this,e).delete(e);return this.size-=t?1:0,t},Xn.prototype.get=function(e){return fi(this,e).get(e)},Xn.prototype.has=function(e){return fi(this,e).has(e)},Xn.prototype.set=function(e,t){var n=fi(this,e),r=n.size;return n.set(e,t),this.size+=n.size==r?0:1,this},Kn.prototype.add=Kn.prototype.push=function(e){return this.__data__.set(e,c),this},Kn.prototype.has=function(e){return this.__data__.has(e)},Gn.prototype.clear=function(){this.__data__=new qn,this.size=0},Gn.prototype.delete=function(e){var t=this.__data__,n=t.delete(e);return this.size=t.size,n},Gn.prototype.get=function(e){return this.__data__.get(e)},Gn.prototype.has=function(e){return this.__data__.has(e)},Gn.prototype.set=function(e,t){var n=this.__data__;if(n instanceof qn){var r=n.__data__;if(!kn||r.length<199)return r.push([e,t]),this.size=++n.size,this;n=this.__data__=new Xn(r)}return n.set(e,t),this.size=n.size,this};var pr=Lo(Or),hr=Lo(jr,!0);function vr(e,t){var n=!0;return pr(e,(function(e,r,o){return n=!!t(e,r,o)})),n}function mr(e,t,n){for(var r=-1,o=e.length;++r0&&n(c)?t>1?br(c,t-1,n,r,o):Lt(o,c):r||(o[o.length]=c)}return o}var yr=Io(),wr=Io(!0);function Or(e,t){return e&&yr(e,t,Rc)}function jr(e,t){return e&&wr(e,t,Rc)}function xr(e,t){return Tt(t,(function(t){return Ja(e[t])}))}function Er(e,t){for(var n=0,r=(t=Oo(t,e)).length;null!=e&&nt}function Cr(e,t){return null!=e&&Le.call(e,t)}function Pr(e,t){return null!=e&&t in ke(e)}function Mr(e,t,r){for(var o=r?Rt:Nt,a=e[0].length,c=e.length,u=c,s=n(c),l=1/0,f=[];u--;){var d=e[u];u&&t&&(d=At(d,Zt(t))),l=wn(d.length,l),s[u]=!r&&(t||a>=120&&d.length>=120)?new Kn(u&&d):i}d=e[0];var p=-1,h=s[0];e:for(;++p=c?u:u*("desc"==n[r]?-1:1)}return e.index-t.index}(e,t,n)}))}function Yr(e,t,n){for(var r=-1,o=t.length,i={};++r-1;)c!==e&&Ke.call(c,u,1),Ke.call(e,u,1);return e}function Xr(e,t){for(var n=e?t.length:0,r=n-1;n--;){var o=t[n];if(n==r||o!==i){var i=o;wi(o)?Ke.call(e,o,1):po(e,o)}}return e}function Kr(e,t){return e+vt(xn()*(t-e+1))}function Gr(e,t){var n="";if(!e||t<1||t>v)return n;do{t%2&&(n+=e),(t=vt(t/2))&&(e+=e)}while(t);return n}function Qr(e,t){return Ai(Ci(e,t,iu),e+"")}function Zr(e){return Zn(Wc(e))}function Jr(e,t){var n=Wc(e);return Di(n,ur(t,0,n.length))}function eo(e,t,n,r){if(!nc(e))return e;for(var o=-1,a=(t=Oo(t,e)).length,c=a-1,u=e;null!=u&&++oi?0:i+t),(r=r>i?i:r)<0&&(r+=i),i=t>r?0:r-t>>>0,t>>>=0;for(var a=n(i);++o>>1,a=e[i];null!==a&&!lc(a)&&(n?a<=t:a=200){var s=t?null:Qo(e);if(s)return dn(s);a=!1,o=en,u=new Kn}else u=t?[]:c;e:for(;++r=r?e:oo(e,t,n)}var Eo=rt||function(e){return ht.clearTimeout(e)};function _o(e,t){if(t)return e.slice();var n=e.length,r=$e?$e(n):new e.constructor(n);return e.copy(r),r}function ko(e){var t=new e.constructor(e.byteLength);return new Ve(t).set(new Ve(e)),t}function So(e,t){var n=t?ko(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.length)}function Co(e,t){if(e!==t){var n=e!==i,r=null===e,o=e===e,a=lc(e),c=t!==i,u=null===t,s=t===t,l=lc(t);if(!u&&!l&&!a&&e>t||a&&c&&s&&!u&&!l||r&&c&&s||!n&&s||!o)return 1;if(!r&&!a&&!l&&e1?n[o-1]:i,c=o>2?n[2]:i;for(a=e.length>3&&"function"==typeof a?(o--,a):i,c&&Oi(n[0],n[1],c)&&(a=o<3?i:a,o=1),t=ke(t);++r-1?o[a?t[c]:c]:i}}function Uo(e){return oi((function(t){var n=t.length,r=n,o=Vn.prototype.thru;for(e&&t.reverse();r--;){var c=t[r];if("function"!=typeof c)throw new Pe(a);if(o&&!u&&"wrapper"==ui(c))var u=new Vn([],!0)}for(r=u?r:n;++r1&&y.reverse(),p&&lu))return!1;var l=a.get(e),f=a.get(t);if(l&&f)return l==t&&f==e;var d=-1,p=!0,h=2&n?new Kn:i;for(a.set(e,t),a.set(t,e);++d-1&&e%1==0&&e1?"& ":"")+t[r],t=t.join(n>2?", ":" "),e.replace(se,"{\n/* [wrapped with "+t+"] */\n")}(r,function(e,t){return Ct(b,(function(n){var r="_."+n[0];t&n[1]&&!Nt(e,r)&&e.push(r)})),e.sort()}(function(e){var t=e.match(le);return t?t[1].split(fe):[]}(r),n)))}function Ii(e){var t=0,n=0;return function(){var r=On(),o=16-(r-n);if(n=r,o>0){if(++t>=800)return arguments[0]}else t=0;return e.apply(i,arguments)}}function Di(e,t){var n=-1,r=e.length,o=r-1;for(t=t===i?r:t;++n1?e[t-1]:i;return n="function"==typeof n?(e.pop(),n):i,ca(e,n)}));function ha(e){var t=Un(e);return t.__chain__=!0,t}function va(e,t){return t(e)}var ma=oi((function(e){var t=e.length,n=t?e[0]:0,r=this.__wrapped__,o=function(t){return cr(t,e)};return!(t>1||this.__actions__.length)&&r instanceof $n&&wi(n)?((r=r.slice(n,+n+(t?1:0))).__actions__.push({func:va,args:[o],thisArg:i}),new Vn(r,this.__chain__).thru((function(e){return t&&!e.length&&e.push(i),e}))):this.thru(o)}));var ga=Ro((function(e,t,n){Le.call(e,n)?++e[n]:ar(e,n,1)}));var ba=Fo($i),ya=Fo(Yi);function wa(e,t){return(Ya(e)?Ct:pr)(e,li(t,3))}function Oa(e,t){return(Ya(e)?Pt:hr)(e,li(t,3))}var ja=Ro((function(e,t,n){Le.call(e,n)?e[n].push(t):ar(e,n,[t])}));var xa=Qr((function(e,t,r){var o=-1,i="function"==typeof t,a=Xa(e)?n(e.length):[];return pr(e,(function(e){a[++o]=i?kt(t,e,r):Tr(e,t,r)})),a})),Ea=Ro((function(e,t,n){ar(e,n,t)}));function _a(e,t){return(Ya(e)?At:Fr)(e,li(t,3))}var ka=Ro((function(e,t,n){e[n?0:1].push(t)}),(function(){return[[],[]]}));var Sa=Qr((function(e,t){if(null==e)return[];var n=t.length;return n>1&&Oi(e,t[0],t[1])?t=[]:n>2&&Oi(t[0],t[1],t[2])&&(t=[t[0]]),$r(e,br(t,1),[])})),Ca=st||function(){return ht.Date.now()};function Pa(e,t,n){return t=n?i:t,t=e&&null==t?e.length:t,Jo(e,d,i,i,i,i,t)}function Ma(e,t){var n;if("function"!=typeof t)throw new Pe(a);return e=mc(e),function(){return--e>0&&(n=t.apply(this,arguments)),e<=1&&(t=i),n}}var Ta=Qr((function(e,t,n){var r=1;if(n.length){var o=fn(n,si(Ta));r|=l}return Jo(e,r,t,n,o)})),Na=Qr((function(e,t,n){var r=3;if(n.length){var o=fn(n,si(Na));r|=l}return Jo(t,r,e,n,o)}));function Ra(e,t,n){var r,o,c,u,s,l,f=0,d=!1,p=!1,h=!0;if("function"!=typeof e)throw new Pe(a);function v(t){var n=r,a=o;return r=o=i,f=t,u=e.apply(a,n)}function m(e){return f=e,s=Ri(b,t),d?v(e):u}function g(e){var n=e-l;return l===i||n>=t||n<0||p&&e-f>=c}function b(){var e=Ca();if(g(e))return y(e);s=Ri(b,function(e){var n=t-(e-l);return p?wn(n,c-(e-f)):n}(e))}function y(e){return s=i,h&&r?v(e):(r=o=i,u)}function w(){var e=Ca(),n=g(e);if(r=arguments,o=this,l=e,n){if(s===i)return m(l);if(p)return Eo(s),s=Ri(b,t),v(l)}return s===i&&(s=Ri(b,t)),u}return t=bc(t)||0,nc(n)&&(d=!!n.leading,c=(p="maxWait"in n)?yn(bc(n.maxWait)||0,t):c,h="trailing"in n?!!n.trailing:h),w.cancel=function(){s!==i&&Eo(s),f=0,r=l=o=s=i},w.flush=function(){return s===i?u:y(Ca())},w}var Aa=Qr((function(e,t){return fr(e,1,t)})),La=Qr((function(e,t,n){return fr(e,bc(t)||0,n)}));function Ia(e,t){if("function"!=typeof e||null!=t&&"function"!=typeof t)throw new Pe(a);var n=function n(){var r=arguments,o=t?t.apply(this,r):r[0],i=n.cache;if(i.has(o))return i.get(o);var a=e.apply(this,r);return n.cache=i.set(o,a)||i,a};return n.cache=new(Ia.Cache||Xn),n}function Da(e){if("function"!=typeof e)throw new Pe(a);return function(){var t=arguments;switch(t.length){case 0:return!e.call(this);case 1:return!e.call(this,t[0]);case 2:return!e.call(this,t[0],t[1]);case 3:return!e.call(this,t[0],t[1],t[2])}return!e.apply(this,t)}}Ia.Cache=Xn;var za=jo((function(e,t){var n=(t=1==t.length&&Ya(t[0])?At(t[0],Zt(li())):At(br(t,1),Zt(li()))).length;return Qr((function(r){for(var o=-1,i=wn(r.length,n);++o=t})),$a=Nr(function(){return arguments}())?Nr:function(e){return rc(e)&&Le.call(e,"callee")&&!Xe.call(e,"callee")},Ya=n.isArray,qa=wt?Zt(wt):function(e){return rc(e)&&kr(e)==L};function Xa(e){return null!=e&&tc(e.length)&&!Ja(e)}function Ka(e){return rc(e)&&Xa(e)}var Ga=bt||bu,Qa=Ot?Zt(Ot):function(e){return rc(e)&&kr(e)==j};function Za(e){if(!rc(e))return!1;var t=kr(e);return t==x||"[object DOMException]"==t||"string"==typeof e.message&&"string"==typeof e.name&&!ac(e)}function Ja(e){if(!nc(e))return!1;var t=kr(e);return t==E||t==_||"[object AsyncFunction]"==t||"[object Proxy]"==t}function ec(e){return"number"==typeof e&&e==mc(e)}function tc(e){return"number"==typeof e&&e>-1&&e%1==0&&e<=v}function nc(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}function rc(e){return null!=e&&"object"==typeof e}var oc=jt?Zt(jt):function(e){return rc(e)&&mi(e)==k};function ic(e){return"number"==typeof e||rc(e)&&kr(e)==S}function ac(e){if(!rc(e)||kr(e)!=C)return!1;var t=Ye(e);if(null===t)return!0;var n=Le.call(t,"constructor")&&t.constructor;return"function"==typeof n&&n instanceof n&&Ae.call(n)==Be}var cc=xt?Zt(xt):function(e){return rc(e)&&kr(e)==M};var uc=Et?Zt(Et):function(e){return rc(e)&&mi(e)==T};function sc(e){return"string"==typeof e||!Ya(e)&&rc(e)&&kr(e)==N}function lc(e){return"symbol"==typeof e||rc(e)&&kr(e)==R}var fc=_t?Zt(_t):function(e){return rc(e)&&tc(e.length)&&!!ct[kr(e)]};var dc=Xo(Br),pc=Xo((function(e,t){return e<=t}));function hc(e){if(!e)return[];if(Xa(e))return sc(e)?vn(e):To(e);if(Qe&&e[Qe])return function(e){for(var t,n=[];!(t=e.next()).done;)n.push(t.value);return n}(e[Qe]());var t=mi(e);return(t==k?sn:t==T?dn:Wc)(e)}function vc(e){return e?(e=bc(e))===h||e===-1/0?17976931348623157e292*(e<0?-1:1):e===e?e:0:0===e?e:0}function mc(e){var t=vc(e),n=t%1;return t===t?n?t-n:t:0}function gc(e){return e?ur(mc(e),0,g):0}function bc(e){if("number"==typeof e)return e;if(lc(e))return m;if(nc(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=nc(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=Qt(e);var n=be.test(e);return n||we.test(e)?ft(e.slice(2),n?2:8):ge.test(e)?m:+e}function yc(e){return No(e,Ac(e))}function wc(e){return null==e?"":lo(e)}var Oc=Ao((function(e,t){if(_i(t)||Xa(t))No(t,Rc(t),e);else for(var n in t)Le.call(t,n)&&nr(e,n,t[n])})),jc=Ao((function(e,t){No(t,Ac(t),e)})),xc=Ao((function(e,t,n,r){No(t,Ac(t),e,r)})),Ec=Ao((function(e,t,n,r){No(t,Rc(t),e,r)})),_c=oi(cr);var kc=Qr((function(e,t){e=ke(e);var n=-1,r=t.length,o=r>2?t[2]:i;for(o&&Oi(t[0],t[1],o)&&(r=1);++n1),t})),No(e,ai(e),n),r&&(n=sr(n,7,ni));for(var o=t.length;o--;)po(n,t[o]);return n}));var zc=oi((function(e,t){return null==e?{}:function(e,t){return Yr(e,t,(function(t,n){return Pc(e,n)}))}(e,t)}));function Bc(e,t){if(null==e)return{};var n=At(ai(e),(function(e){return[e]}));return t=li(t),Yr(e,n,(function(e,n){return t(e,n[0])}))}var Fc=Zo(Rc),Uc=Zo(Ac);function Wc(e){return null==e?[]:Jt(e,Rc(e))}var Hc=zo((function(e,t,n){return t=t.toLowerCase(),e+(n?Vc(t):t)}));function Vc(e){return Zc(wc(e).toLowerCase())}function $c(e){return(e=wc(e))&&e.replace(je,on).replace(et,"")}var Yc=zo((function(e,t,n){return e+(n?"-":"")+t.toLowerCase()})),qc=zo((function(e,t,n){return e+(n?" ":"")+t.toLowerCase()})),Xc=Do("toLowerCase");var Kc=zo((function(e,t,n){return e+(n?"_":"")+t.toLowerCase()}));var Gc=zo((function(e,t,n){return e+(n?" ":"")+Zc(t)}));var Qc=zo((function(e,t,n){return e+(n?" ":"")+t.toUpperCase()})),Zc=Do("toUpperCase");function Jc(e,t,n){return e=wc(e),(t=n?i:t)===i?function(e){return ot.test(e)}(e)?function(e){return e.match(nt)||[]}(e):function(e){return e.match(de)||[]}(e):e.match(t)||[]}var eu=Qr((function(e,t){try{return kt(e,i,t)}catch(n){return Za(n)?n:new o(n)}})),tu=oi((function(e,t){return Ct(t,(function(t){t=Bi(t),ar(e,t,Ta(e[t],e))})),e}));function nu(e){return function(){return e}}var ru=Uo(),ou=Uo(!0);function iu(e){return e}function au(e){return Ir("function"==typeof e?e:sr(e,1))}var cu=Qr((function(e,t){return function(n){return Tr(n,e,t)}})),uu=Qr((function(e,t){return function(n){return Tr(e,n,t)}}));function su(e,t,n){var r=Rc(t),o=xr(t,r);null!=n||nc(t)&&(o.length||!r.length)||(n=t,t=e,e=this,o=xr(t,Rc(t)));var i=!(nc(n)&&"chain"in n)||!!n.chain,a=Ja(e);return Ct(o,(function(n){var r=t[n];e[n]=r,a&&(e.prototype[n]=function(){var t=this.__chain__;if(i||t){var n=e(this.__wrapped__),o=n.__actions__=To(this.__actions__);return o.push({func:r,args:arguments,thisArg:e}),n.__chain__=t,n}return r.apply(e,Lt([this.value()],arguments))})})),e}function lu(){}var fu=$o(At),du=$o(Mt),pu=$o(zt);function hu(e){return ji(e)?Yt(Bi(e)):function(e){return function(t){return Er(t,e)}}(e)}var vu=qo(),mu=qo(!0);function gu(){return[]}function bu(){return!1}var yu=Vo((function(e,t){return e+t}),0),wu=Go("ceil"),Ou=Vo((function(e,t){return e/t}),1),ju=Go("floor");var xu=Vo((function(e,t){return e*t}),1),Eu=Go("round"),_u=Vo((function(e,t){return e-t}),0);return Un.after=function(e,t){if("function"!=typeof t)throw new Pe(a);return e=mc(e),function(){if(--e<1)return t.apply(this,arguments)}},Un.ary=Pa,Un.assign=Oc,Un.assignIn=jc,Un.assignInWith=xc,Un.assignWith=Ec,Un.at=_c,Un.before=Ma,Un.bind=Ta,Un.bindAll=tu,Un.bindKey=Na,Un.castArray=function(){if(!arguments.length)return[];var e=arguments[0];return Ya(e)?e:[e]},Un.chain=ha,Un.chunk=function(e,t,r){t=(r?Oi(e,t,r):t===i)?1:yn(mc(t),0);var o=null==e?0:e.length;if(!o||t<1)return[];for(var a=0,c=0,u=n(pt(o/t));ao?0:o+n),(r=r===i||r>o?o:mc(r))<0&&(r+=o),r=n>r?0:gc(r);n>>0)?(e=wc(e))&&("string"==typeof t||null!=t&&!cc(t))&&!(t=lo(t))&&un(e)?xo(vn(e),0,n):e.split(t,n):[]},Un.spread=function(e,t){if("function"!=typeof e)throw new Pe(a);return t=null==t?0:yn(mc(t),0),Qr((function(n){var r=n[t],o=xo(n,0,t);return r&&Lt(o,r),kt(e,this,o)}))},Un.tail=function(e){var t=null==e?0:e.length;return t?oo(e,1,t):[]},Un.take=function(e,t,n){return e&&e.length?oo(e,0,(t=n||t===i?1:mc(t))<0?0:t):[]},Un.takeRight=function(e,t,n){var r=null==e?0:e.length;return r?oo(e,(t=r-(t=n||t===i?1:mc(t)))<0?0:t,r):[]},Un.takeRightWhile=function(e,t){return e&&e.length?vo(e,li(t,3),!1,!0):[]},Un.takeWhile=function(e,t){return e&&e.length?vo(e,li(t,3)):[]},Un.tap=function(e,t){return t(e),e},Un.throttle=function(e,t,n){var r=!0,o=!0;if("function"!=typeof e)throw new Pe(a);return nc(n)&&(r="leading"in n?!!n.leading:r,o="trailing"in n?!!n.trailing:o),Ra(e,t,{leading:r,maxWait:t,trailing:o})},Un.thru=va,Un.toArray=hc,Un.toPairs=Fc,Un.toPairsIn=Uc,Un.toPath=function(e){return Ya(e)?At(e,Bi):lc(e)?[e]:To(zi(wc(e)))},Un.toPlainObject=yc,Un.transform=function(e,t,n){var r=Ya(e),o=r||Ga(e)||fc(e);if(t=li(t,4),null==n){var i=e&&e.constructor;n=o?r?new i:[]:nc(e)&&Ja(i)?Wn(Ye(e)):{}}return(o?Ct:Or)(e,(function(e,r,o){return t(n,e,r,o)})),n},Un.unary=function(e){return Pa(e,1)},Un.union=ra,Un.unionBy=oa,Un.unionWith=ia,Un.uniq=function(e){return e&&e.length?fo(e):[]},Un.uniqBy=function(e,t){return e&&e.length?fo(e,li(t,2)):[]},Un.uniqWith=function(e,t){return t="function"==typeof t?t:i,e&&e.length?fo(e,i,t):[]},Un.unset=function(e,t){return null==e||po(e,t)},Un.unzip=aa,Un.unzipWith=ca,Un.update=function(e,t,n){return null==e?e:ho(e,t,wo(n))},Un.updateWith=function(e,t,n,r){return r="function"==typeof r?r:i,null==e?e:ho(e,t,wo(n),r)},Un.values=Wc,Un.valuesIn=function(e){return null==e?[]:Jt(e,Ac(e))},Un.without=ua,Un.words=Jc,Un.wrap=function(e,t){return Ba(wo(t),e)},Un.xor=sa,Un.xorBy=la,Un.xorWith=fa,Un.zip=da,Un.zipObject=function(e,t){return bo(e||[],t||[],nr)},Un.zipObjectDeep=function(e,t){return bo(e||[],t||[],eo)},Un.zipWith=pa,Un.entries=Fc,Un.entriesIn=Uc,Un.extend=jc,Un.extendWith=xc,su(Un,Un),Un.add=yu,Un.attempt=eu,Un.camelCase=Hc,Un.capitalize=Vc,Un.ceil=wu,Un.clamp=function(e,t,n){return n===i&&(n=t,t=i),n!==i&&(n=(n=bc(n))===n?n:0),t!==i&&(t=(t=bc(t))===t?t:0),ur(bc(e),t,n)},Un.clone=function(e){return sr(e,4)},Un.cloneDeep=function(e){return sr(e,5)},Un.cloneDeepWith=function(e,t){return sr(e,5,t="function"==typeof t?t:i)},Un.cloneWith=function(e,t){return sr(e,4,t="function"==typeof t?t:i)},Un.conformsTo=function(e,t){return null==t||lr(e,t,Rc(t))},Un.deburr=$c,Un.defaultTo=function(e,t){return null==e||e!==e?t:e},Un.divide=Ou,Un.endsWith=function(e,t,n){e=wc(e),t=lo(t);var r=e.length,o=n=n===i?r:ur(mc(n),0,r);return(n-=t.length)>=0&&e.slice(n,o)==t},Un.eq=Wa,Un.escape=function(e){return(e=wc(e))&&Z.test(e)?e.replace(G,an):e},Un.escapeRegExp=function(e){return(e=wc(e))&&ae.test(e)?e.replace(ie,"\\$&"):e},Un.every=function(e,t,n){var r=Ya(e)?Mt:vr;return n&&Oi(e,t,n)&&(t=i),r(e,li(t,3))},Un.find=ba,Un.findIndex=$i,Un.findKey=function(e,t){return Ft(e,li(t,3),Or)},Un.findLast=ya,Un.findLastIndex=Yi,Un.findLastKey=function(e,t){return Ft(e,li(t,3),jr)},Un.floor=ju,Un.forEach=wa,Un.forEachRight=Oa,Un.forIn=function(e,t){return null==e?e:yr(e,li(t,3),Ac)},Un.forInRight=function(e,t){return null==e?e:wr(e,li(t,3),Ac)},Un.forOwn=function(e,t){return e&&Or(e,li(t,3))},Un.forOwnRight=function(e,t){return e&&jr(e,li(t,3))},Un.get=Cc,Un.gt=Ha,Un.gte=Va,Un.has=function(e,t){return null!=e&&gi(e,t,Cr)},Un.hasIn=Pc,Un.head=Xi,Un.identity=iu,Un.includes=function(e,t,n,r){e=Xa(e)?e:Wc(e),n=n&&!r?mc(n):0;var o=e.length;return n<0&&(n=yn(o+n,0)),sc(e)?n<=o&&e.indexOf(t,n)>-1:!!o&&Wt(e,t,n)>-1},Un.indexOf=function(e,t,n){var r=null==e?0:e.length;if(!r)return-1;var o=null==n?0:mc(n);return o<0&&(o=yn(r+o,0)),Wt(e,t,o)},Un.inRange=function(e,t,n){return t=vc(t),n===i?(n=t,t=0):n=vc(n),function(e,t,n){return e>=wn(t,n)&&e=-9007199254740991&&e<=v},Un.isSet=uc,Un.isString=sc,Un.isSymbol=lc,Un.isTypedArray=fc,Un.isUndefined=function(e){return e===i},Un.isWeakMap=function(e){return rc(e)&&mi(e)==A},Un.isWeakSet=function(e){return rc(e)&&"[object WeakSet]"==kr(e)},Un.join=function(e,t){return null==e?"":Bt.call(e,t)},Un.kebabCase=Yc,Un.last=Zi,Un.lastIndexOf=function(e,t,n){var r=null==e?0:e.length;if(!r)return-1;var o=r;return n!==i&&(o=(o=mc(n))<0?yn(r+o,0):wn(o,r-1)),t===t?function(e,t,n){for(var r=n+1;r--;)if(e[r]===t)return r;return r}(e,t,o):Ut(e,Vt,o,!0)},Un.lowerCase=qc,Un.lowerFirst=Xc,Un.lt=dc,Un.lte=pc,Un.max=function(e){return e&&e.length?mr(e,iu,Sr):i},Un.maxBy=function(e,t){return e&&e.length?mr(e,li(t,2),Sr):i},Un.mean=function(e){return $t(e,iu)},Un.meanBy=function(e,t){return $t(e,li(t,2))},Un.min=function(e){return e&&e.length?mr(e,iu,Br):i},Un.minBy=function(e,t){return e&&e.length?mr(e,li(t,2),Br):i},Un.stubArray=gu,Un.stubFalse=bu,Un.stubObject=function(){return{}},Un.stubString=function(){return""},Un.stubTrue=function(){return!0},Un.multiply=xu,Un.nth=function(e,t){return e&&e.length?Vr(e,mc(t)):i},Un.noConflict=function(){return ht._===this&&(ht._=Fe),this},Un.noop=lu,Un.now=Ca,Un.pad=function(e,t,n){e=wc(e);var r=(t=mc(t))?hn(e):0;if(!t||r>=t)return e;var o=(t-r)/2;return Yo(vt(o),n)+e+Yo(pt(o),n)},Un.padEnd=function(e,t,n){e=wc(e);var r=(t=mc(t))?hn(e):0;return t&&rt){var r=e;e=t,t=r}if(n||e%1||t%1){var o=xn();return wn(e+o*(t-e+lt("1e-"+((o+"").length-1))),t)}return Kr(e,t)},Un.reduce=function(e,t,n){var r=Ya(e)?It:Xt,o=arguments.length<3;return r(e,li(t,4),n,o,pr)},Un.reduceRight=function(e,t,n){var r=Ya(e)?Dt:Xt,o=arguments.length<3;return r(e,li(t,4),n,o,hr)},Un.repeat=function(e,t,n){return t=(n?Oi(e,t,n):t===i)?1:mc(t),Gr(wc(e),t)},Un.replace=function(){var e=arguments,t=wc(e[0]);return e.length<3?t:t.replace(e[1],e[2])},Un.result=function(e,t,n){var r=-1,o=(t=Oo(t,e)).length;for(o||(o=1,e=i);++rv)return[];var n=g,r=wn(e,g);t=li(t),e-=g;for(var o=Gt(r,t);++n=a)return e;var u=n-hn(r);if(u<1)return r;var s=c?xo(c,0,u).join(""):e.slice(0,u);if(o===i)return s+r;if(c&&(u+=s.length-u),cc(o)){if(e.slice(u).search(o)){var l,f=s;for(o.global||(o=Se(o.source,wc(me.exec(o))+"g")),o.lastIndex=0;l=o.exec(f);)var d=l.index;s=s.slice(0,d===i?u:d)}}else if(e.indexOf(lo(o),u)!=u){var p=s.lastIndexOf(o);p>-1&&(s=s.slice(0,p))}return s+r},Un.unescape=function(e){return(e=wc(e))&&Q.test(e)?e.replace(K,gn):e},Un.uniqueId=function(e){var t=++Ie;return wc(e)+t},Un.upperCase=Qc,Un.upperFirst=Zc,Un.each=wa,Un.eachRight=Oa,Un.first=Xi,su(Un,function(){var e={};return Or(Un,(function(t,n){Le.call(Un.prototype,n)||(e[n]=t)})),e}(),{chain:!1}),Un.VERSION="4.17.21",Ct(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(e){Un[e].placeholder=Un})),Ct(["drop","take"],(function(e,t){$n.prototype[e]=function(n){n=n===i?1:yn(mc(n),0);var r=this.__filtered__&&!t?new $n(this):this.clone();return r.__filtered__?r.__takeCount__=wn(n,r.__takeCount__):r.__views__.push({size:wn(n,g),type:e+(r.__dir__<0?"Right":"")}),r},$n.prototype[e+"Right"]=function(t){return this.reverse()[e](t).reverse()}})),Ct(["filter","map","takeWhile"],(function(e,t){var n=t+1,r=1==n||3==n;$n.prototype[e]=function(e){var t=this.clone();return t.__iteratees__.push({iteratee:li(e,3),type:n}),t.__filtered__=t.__filtered__||r,t}})),Ct(["head","last"],(function(e,t){var n="take"+(t?"Right":"");$n.prototype[e]=function(){return this[n](1).value()[0]}})),Ct(["initial","tail"],(function(e,t){var n="drop"+(t?"":"Right");$n.prototype[e]=function(){return this.__filtered__?new $n(this):this[n](1)}})),$n.prototype.compact=function(){return this.filter(iu)},$n.prototype.find=function(e){return this.filter(e).head()},$n.prototype.findLast=function(e){return this.reverse().find(e)},$n.prototype.invokeMap=Qr((function(e,t){return"function"==typeof e?new $n(this):this.map((function(n){return Tr(n,e,t)}))})),$n.prototype.reject=function(e){return this.filter(Da(li(e)))},$n.prototype.slice=function(e,t){e=mc(e);var n=this;return n.__filtered__&&(e>0||t<0)?new $n(n):(e<0?n=n.takeRight(-e):e&&(n=n.drop(e)),t!==i&&(n=(t=mc(t))<0?n.dropRight(-t):n.take(t-e)),n)},$n.prototype.takeRightWhile=function(e){return this.reverse().takeWhile(e).reverse()},$n.prototype.toArray=function(){return this.take(g)},Or($n.prototype,(function(e,t){var n=/^(?:filter|find|map|reject)|While$/.test(t),r=/^(?:head|last)$/.test(t),o=Un[r?"take"+("last"==t?"Right":""):t],a=r||/^find/.test(t);o&&(Un.prototype[t]=function(){var t=this.__wrapped__,c=r?[1]:arguments,u=t instanceof $n,s=c[0],l=u||Ya(t),f=function(e){var t=o.apply(Un,Lt([e],c));return r&&d?t[0]:t};l&&n&&"function"==typeof s&&1!=s.length&&(u=l=!1);var d=this.__chain__,p=!!this.__actions__.length,h=a&&!d,v=u&&!p;if(!a&&l){t=v?t:new $n(this);var m=e.apply(t,c);return m.__actions__.push({func:va,args:[f],thisArg:i}),new Vn(m,d)}return h&&v?e.apply(this,c):(m=this.thru(f),h?r?m.value()[0]:m.value():m)})})),Ct(["pop","push","shift","sort","splice","unshift"],(function(e){var t=Me[e],n=/^(?:push|sort|unshift)$/.test(e)?"tap":"thru",r=/^(?:pop|shift)$/.test(e);Un.prototype[e]=function(){var e=arguments;if(r&&!this.__chain__){var o=this.value();return t.apply(Ya(o)?o:[],e)}return this[n]((function(n){return t.apply(Ya(n)?n:[],e)}))}})),Or($n.prototype,(function(e,t){var n=Un[t];if(n){var r=n.name+"";Le.call(Nn,r)||(Nn[r]=[]),Nn[r].push({name:t,func:n})}})),Nn[Wo(i,2).name]=[{name:"wrapper",func:i}],$n.prototype.clone=function(){var e=new $n(this.__wrapped__);return e.__actions__=To(this.__actions__),e.__dir__=this.__dir__,e.__filtered__=this.__filtered__,e.__iteratees__=To(this.__iteratees__),e.__takeCount__=this.__takeCount__,e.__views__=To(this.__views__),e},$n.prototype.reverse=function(){if(this.__filtered__){var e=new $n(this);e.__dir__=-1,e.__filtered__=!0}else(e=this.clone()).__dir__*=-1;return e},$n.prototype.value=function(){var e=this.__wrapped__.value(),t=this.__dir__,n=Ya(e),r=t<0,o=n?e.length:0,i=function(e,t,n){var r=-1,o=n.length;for(;++r=this.__values__.length;return{done:e,value:e?i:this.__values__[this.__index__++]}},Un.prototype.plant=function(e){for(var t,n=this;n instanceof Hn;){var r=Ui(n);r.__index__=0,r.__values__=i,t?o.__wrapped__=r:t=r;var o=r;n=n.__wrapped__}return o.__wrapped__=e,t},Un.prototype.reverse=function(){var e=this.__wrapped__;if(e instanceof $n){var t=e;return this.__actions__.length&&(t=new $n(this)),(t=t.reverse()).__actions__.push({func:va,args:[na],thisArg:i}),new Vn(t,this.__chain__)}return this.thru(na)},Un.prototype.toJSON=Un.prototype.valueOf=Un.prototype.value=function(){return mo(this.__wrapped__,this.__actions__)},Un.prototype.first=Un.prototype.head,Qe&&(Un.prototype[Qe]=function(){return this}),Un}();ht._=bn,(o=function(){return bn}.call(t,n,t,r))===i||(r.exports=o)}).call(this)}).call(this,n(160),n(124)(e))},,function(e,t,n){"use strict";n.d(t,"a",(function(){return c}));var r=n(2),o=n(0),i=n(287),a=n(1);function c(e,t){var n=function(n,o){return Object(a.jsx)(i.a,Object(r.a)({"data-testid":"".concat(t,"Icon"),ref:o},n,{children:e}))};return n.muiName=i.a.muiName,o.memo(o.forwardRef(n))}},function(e,t,n){"use strict";n.d(t,"a",(function(){return f})),n.d(t,"b",(function(){return d})),n.d(t,"c",(function(){return p})),n.d(t,"d",(function(){return h})),n.d(t,"e",(function(){return m})),n.d(t,"f",(function(){return g})),n.d(t,"g",(function(){return b})),n.d(t,"h",(function(){return y}));var r=n(12),o=n(0),i=n(42);function a(e,t){if(!e)throw new Error(t)}var c=Object(o.createContext)(null);var u=Object(o.createContext)(null);var s=Object(o.createContext)({outlet:null,matches:[]});function l(e){return Object(o.useContext)(s).outlet}function f(e){a(!1)}function d(e){var t=e.basename,n=void 0===t?"/":t,r=e.children,s=void 0===r?null:r,l=e.location,f=e.navigationType,d=void 0===f?i.a.Pop:f,p=e.navigator,h=e.static,m=void 0!==h&&h;v()&&a(!1);var g=T(n),b=Object(o.useMemo)((function(){return{basename:g,navigator:p,static:m}}),[g,p,m]);"string"===typeof l&&(l=Object(i.f)(l));var y=l,w=y.pathname,O=void 0===w?"/":w,j=y.search,x=void 0===j?"":j,E=y.hash,_=void 0===E?"":E,k=y.state,S=void 0===k?null:k,C=y.key,M=void 0===C?"default":C,N=Object(o.useMemo)((function(){var e=P(O,g);return null==e?null:{pathname:e,search:x,hash:_,state:S,key:M}}),[g,O,x,_,S,M]);return null==N?null:Object(o.createElement)(c.Provider,{value:b},Object(o.createElement)(u.Provider,{children:s,value:{location:N,navigationType:d}}))}function p(e){var t=e.children,n=e.location;return function(e,t){v()||a(!1);var n=Object(o.useContext)(s).matches,r=n[n.length-1],c=r?r.params:{},u=(r&&r.pathname,r?r.pathnameBase:"/");r&&r.route;0;var l,f=m();if(t){var d,p="string"===typeof t?Object(i.f)(t):t;"/"===u||(null==(d=p.pathname)?void 0:d.startsWith(u))||a(!1),l=p}else l=f;var h=l.pathname||"/",g="/"===u?h:h.slice(u.length)||"/",b=function(e,t,n){void 0===n&&(n="/");var r=P(("string"===typeof t?Object(i.f)(t):t).pathname||"/",n);if(null==r)return null;var o=O(e);!function(e){e.sort((function(e,t){return e.score!==t.score?t.score-e.score:function(e,t){return e.length===t.length&&e.slice(0,-1).every((function(e,n){return e===t[n]}))?e[e.length-1]-t[t.length-1]:0}(e.routesMeta.map((function(e){return e.childrenIndex})),t.routesMeta.map((function(e){return e.childrenIndex})))}))}(o);for(var a=null,c=0;null==a&&c0&&(!0===e.index&&a(!1),O(e.children,t,u,c)),(null!=e.path||e.index)&&t.push({path:c,score:E(c,e.index),routesMeta:u})})),t}var j=/^:\w+$/,x=function(e){return"*"===e};function E(e,t){var n=e.split("/"),r=n.length;return n.some(x)&&(r+=-2),t&&(r+=2),n.filter((function(e){return!x(e)})).reduce((function(e,t){return e+(j.test(t)?3:""===t?1:10)}),r)}function _(e,t,n){for(var r=t,o=e.routesMeta,i={},a="/",c=[],u=0;u=0?t[c]:"/"}var s=function(e,t){void 0===t&&(t="/");var n="string"===typeof e?Object(i.f)(e):e,r=n.pathname,o=n.search,a=void 0===o?"":o,c=n.hash,u=void 0===c?"":c;return{pathname:r?r.startsWith("/")?r:function(e,t){var n=t.replace(/\/+$/,"").split("/");return e.split("/").forEach((function(e){".."===e?n.length>1&&n.pop():"."!==e&&n.push(e)})),n.length>1?n.join("/"):"/"}(r,t):t,search:N(a),hash:R(u)}}(o,r);return a&&"/"!==a&&a.endsWith("/")&&!s.pathname.endsWith("/")&&(s.pathname+="/"),s}function P(e,t){if("/"===t)return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;var n=e.charAt(t.length);return n&&"/"!==n?null:e.slice(t.length)||"/"}var M=function(e){return e.join("/").replace(/\/\/+/g,"/")},T=function(e){return e.replace(/\/+$/,"").replace(/^\/*/,"/")},N=function(e){return e&&"?"!==e?e.startsWith("?")?e:"?"+e:""},R=function(e){return e&&"#"!==e?e.startsWith("#")?e:"#"+e:""}},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}n.d(t,"a",(function(){return r}))},function(e,t,n){"use strict";function r(e,t){for(var n=0;n1?"s":"")+" required, but only "+t.length+" present")}n.d(t,"a",(function(){return r}))},function(e,t,n){"use strict";var r=n(286);t.a=r.a},function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));var r=n(3);function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function h(e){if("string"===typeof e||"number"===typeof e)return""+e;var t="";if(Array.isArray(e))for(var n,r=0;re.length)&&(t=e.length);for(var n=0,r=new Array(t);n1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return Math.min(Math.max(e,t),n)},Bt=function(e,t){return{x:zt(e.x,t[0][0],t[1][0]),y:zt(e.y,t[0][1],t[1][1])}},Ft=function(e){var t=Lt(Object(c.useState)(!1),2),n=t[0],r=t[1];return Object(c.useEffect)((function(){if("undefined"!==typeof e){var t=function(t){It(t)||t.key!==e&&t.keyCode!==e||(t.preventDefault(),r(!0))},n=function(t){It(t)||t.key!==e&&t.keyCode!==e||r(!1)},o=function(){return r(!1)};return window.addEventListener("keydown",t),window.addEventListener("keyup",n),window.addEventListener("blur",o),function(){window.removeEventListener("keydown",t),window.removeEventListener("keyup",n),window.removeEventListener("blur",o)}}}),[e,r]),n};function Ut(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Wt(e){for(var t=1;t2&&void 0!==arguments[2]?arguments[2]:[0,0,1],r=Lt(n,3),o=r[0],i=r[1],a=r[2],c=arguments.length>3&&void 0!==arguments[3]&&arguments[3],u=arguments.length>4&&void 0!==arguments[4]&&arguments[4],s=Gt({x:(t.x-o)/a,y:(t.y-i)/a,width:t.width/a,height:t.height/a});return e.filter((function(e){var t=e.selectable,n=void 0===t||t,r=e.__rf,o=r.position,i=r.width,a=r.height,l=r.isDragging;if(u&&!n)return!1;var f=Gt(Wt(Wt({},o),{},{width:i,height:a})),d=Math.max(0,Math.min(s.x2,f.x2)-Math.max(s.x,f.x)),p=Math.max(0,Math.min(s.y2,f.y2)-Math.max(s.y,f.y)),h=Math.ceil(d*p);return!(null!==i&&null!==a&&!l)||(c?h>0:h>=i*a)}))},en=function(e,t){var n=e.map((function(e){return e.id}));return t.filter((function(e){return n.includes(e.source)||n.includes(e.target)}))},tn=function(e,t){return[].concat(At(e.map((function(e){var t=Wt({},e);return t.position=t.__rf.position,delete t.__rf,t}))),At(t.map((function(e){return Wt({},e)}))))},nn=function(e){return function(){var t=e.getState(),n=t.nodes,r=void 0===n?[]:n,o=t.edges;return tn(r,void 0===o?[]:o)}},rn=function(e){return function(){var t=e.getState(),n=t.nodes,r=void 0===n?[]:n,o=t.edges,i=void 0===o?[]:o,a=t.transform;return{elements:tn(r,i),position:[a[0],a[1]],zoom:a[2]}}},on=function(e,t,n,r,o){var i=arguments.length>5&&void 0!==arguments[5]?arguments[5]:.1,a=t/(e.width*(1+i)),c=n/(e.height*(1+i)),u=Math.min(a,c),s=zt(u,r,o),l=e.x+e.width/2,f=e.y+e.height/2,d=t/2-l*s,p=n/2-f*s;return[d,p,s]},an={value:function(){}};function cn(){for(var e,t=0,n=arguments.length,r={};t=0&&(n=e.slice(r+1),e=e.slice(0,r)),e&&!t.hasOwnProperty(e))throw new Error("unknown type: "+e);return{type:e,name:n}}))}function ln(e,t){for(var n,r=0,o=e.length;r0)for(var n,r,o=new Array(n),i=0;i=0&&"xmlns"!==(t=e.slice(0,n))&&(e=e.slice(n+1)),pn.hasOwnProperty(t)?{space:pn[t],local:e}:e}function vn(e){return function(){var t=this.ownerDocument,n=this.namespaceURI;return n===dn&&t.documentElement.namespaceURI===dn?t.createElement(e):t.createElementNS(n,e)}}function mn(e){return function(){return this.ownerDocument.createElementNS(e.space,e.local)}}function gn(e){var t=hn(e);return(t.local?mn:vn)(t)}function bn(){}function yn(e){return null==e?bn:function(){return this.querySelector(e)}}function wn(e){return null==e?[]:Array.isArray(e)?e:Array.from(e)}function On(){return[]}function jn(e){return null==e?On:function(){return this.querySelectorAll(e)}}function xn(e){return function(){return this.matches(e)}}function En(e){return function(t){return t.matches(e)}}var _n=Array.prototype.find;function kn(){return this.firstElementChild}var Sn=Array.prototype.filter;function Cn(){return Array.from(this.children)}function Pn(e){return new Array(e.length)}function Mn(e,t){this.ownerDocument=e.ownerDocument,this.namespaceURI=e.namespaceURI,this._next=null,this._parent=e,this.__data__=t}function Tn(e){return function(){return e}}function Nn(e,t,n,r,o,i){for(var a,c=0,u=t.length,s=i.length;ct?1:e>=t?0:NaN}function Dn(e){return function(){this.removeAttribute(e)}}function zn(e){return function(){this.removeAttributeNS(e.space,e.local)}}function Bn(e,t){return function(){this.setAttribute(e,t)}}function Fn(e,t){return function(){this.setAttributeNS(e.space,e.local,t)}}function Un(e,t){return function(){var n=t.apply(this,arguments);null==n?this.removeAttribute(e):this.setAttribute(e,n)}}function Wn(e,t){return function(){var n=t.apply(this,arguments);null==n?this.removeAttributeNS(e.space,e.local):this.setAttributeNS(e.space,e.local,n)}}function Hn(e){return e.ownerDocument&&e.ownerDocument.defaultView||e.document&&e||e.defaultView}function Vn(e){return function(){this.style.removeProperty(e)}}function $n(e,t,n){return function(){this.style.setProperty(e,t,n)}}function Yn(e,t,n){return function(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(e):this.style.setProperty(e,r,n)}}function qn(e,t){return e.style.getPropertyValue(t)||Hn(e).getComputedStyle(e,null).getPropertyValue(t)}function Xn(e){return function(){delete this[e]}}function Kn(e,t){return function(){this[e]=t}}function Gn(e,t){return function(){var n=t.apply(this,arguments);null==n?delete this[e]:this[e]=n}}function Qn(e){return e.trim().split(/^|\s+/)}function Zn(e){return e.classList||new Jn(e)}function Jn(e){this._node=e,this._names=Qn(e.getAttribute("class")||"")}function er(e,t){for(var n=Zn(e),r=-1,o=t.length;++r=0&&(t=e.slice(n+1),e=e.slice(0,n)),{type:e,name:t}}))}function br(e){return function(){var t=this.__on;if(t){for(var n,r=0,o=-1,i=t.length;r=0&&(this._names.splice(t,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(e){return this._names.indexOf(e)>=0}};var Er=[null];function _r(e,t){this._groups=e,this._parents=t}function kr(){return new _r([[document.documentElement]],Er)}function Sr(e){return"string"===typeof e?new _r([[document.querySelector(e)]],[document.documentElement]):new _r([[e]],Er)}function Cr(e,t){if(e=function(e){for(var t;t=e.sourceEvent;)e=t;return e}(e),void 0===t&&(t=e.currentTarget),t){var n=t.ownerSVGElement||t;if(n.createSVGPoint){var r=n.createSVGPoint();return r.x=e.clientX,r.y=e.clientY,[(r=r.matrixTransform(t.getScreenCTM().inverse())).x,r.y]}if(t.getBoundingClientRect){var o=t.getBoundingClientRect();return[e.clientX-o.left-t.clientLeft,e.clientY-o.top-t.clientTop]}}return[e.pageX,e.pageY]}_r.prototype=kr.prototype=Object(r.a)({constructor:_r,select:function(e){"function"!==typeof e&&(e=yn(e));for(var t=this._groups,n=t.length,r=new Array(n),o=0;o=O&&(O=w+1);!(y=m[O])&&++O=0;)(r=o[i])&&(a&&4^r.compareDocumentPosition(a)&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(e){function t(t,n){return t&&n?e(t.__data__,n.__data__):!t-!n}e||(e=In);for(var n=this._groups,r=n.length,o=new Array(r),i=0;i1?this.each((null==t?Vn:"function"===typeof t?Yn:$n)(e,t,null==n?"":n)):qn(this.node(),e)},property:function(e,t){return arguments.length>1?this.each((null==t?Xn:"function"===typeof t?Gn:Kn)(e,t)):this.node()[e]},classed:function(e,t){var n=Qn(e+"");if(arguments.length<2){for(var r=Zn(this.node()),o=-1,i=n.length;++o>8&15|t>>4&240,t>>4&15|240&t,(15&t)<<4|15&t,1):8===n?Jr(t>>24&255,t>>16&255,t>>8&255,(255&t)/255):4===n?Jr(t>>12&15|t>>8&240,t>>8&15|t>>4&240,t>>4&15|240&t,((15&t)<<4|15&t)/255):null):(t=Wr.exec(e))?new no(t[1],t[2],t[3],1):(t=Hr.exec(e))?new no(255*t[1]/100,255*t[2]/100,255*t[3]/100,1):(t=Vr.exec(e))?Jr(t[1],t[2],t[3],t[4]):(t=$r.exec(e))?Jr(255*t[1]/100,255*t[2]/100,255*t[3]/100,t[4]):(t=Yr.exec(e))?ao(t[1],t[2]/100,t[3]/100,1):(t=qr.exec(e))?ao(t[1],t[2]/100,t[3]/100,t[4]):Xr.hasOwnProperty(e)?Zr(Xr[e]):"transparent"===e?new no(NaN,NaN,NaN,0):null}function Zr(e){return new no(e>>16&255,e>>8&255,255&e,1)}function Jr(e,t,n,r){return r<=0&&(e=t=n=NaN),new no(e,t,n,r)}function eo(e){return e instanceof Lr||(e=Qr(e)),e?new no((e=e.rgb()).r,e.g,e.b,e.opacity):new no}function to(e,t,n,r){return 1===arguments.length?eo(e):new no(e,t,n,null==r?1:r)}function no(e,t,n,r){this.r=+e,this.g=+t,this.b=+n,this.opacity=+r}function ro(){return"#"+io(this.r)+io(this.g)+io(this.b)}function oo(){var e=this.opacity;return(1===(e=isNaN(e)?1:Math.max(0,Math.min(1,e)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===e?")":", "+e+")")}function io(e){return((e=Math.max(0,Math.min(255,Math.round(e)||0)))<16?"0":"")+e.toString(16)}function ao(e,t,n,r){return r<=0?e=t=n=NaN:n<=0||n>=1?e=t=NaN:t<=0&&(e=NaN),new uo(e,t,n,r)}function co(e){if(e instanceof uo)return new uo(e.h,e.s,e.l,e.opacity);if(e instanceof Lr||(e=Qr(e)),!e)return new uo;if(e instanceof uo)return e;var t=(e=e.rgb()).r/255,n=e.g/255,r=e.b/255,o=Math.min(t,n,r),i=Math.max(t,n,r),a=NaN,c=i-o,u=(i+o)/2;return c?(a=t===i?(n-r)/c+6*(n0&&u<1?0:a,new uo(a,c,u,e.opacity)}function uo(e,t,n,r){this.h=+e,this.s=+t,this.l=+n,this.opacity=+r}function so(e,t,n){return 255*(e<60?t+(n-t)*e/60:e<180?n:e<240?t+(n-t)*(240-e)/60:t)}Rr(Lr,Qr,{copy:function(e){return Object.assign(new this.constructor,this,e)},displayable:function(){return this.rgb().displayable()},hex:Kr,formatHex:Kr,formatHsl:function(){return co(this).formatHsl()},formatRgb:Gr,toString:Gr}),Rr(no,to,Ar(Lr,{brighter:function(e){return e=null==e?Dr:Math.pow(Dr,e),new no(this.r*e,this.g*e,this.b*e,this.opacity)},darker:function(e){return e=null==e?Ir:Math.pow(Ir,e),new no(this.r*e,this.g*e,this.b*e,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:ro,formatHex:ro,formatRgb:oo,toString:oo})),Rr(uo,(function(e,t,n,r){return 1===arguments.length?co(e):new uo(e,t,n,null==r?1:r)}),Ar(Lr,{brighter:function(e){return e=null==e?Dr:Math.pow(Dr,e),new uo(this.h,this.s,this.l*e,this.opacity)},darker:function(e){return e=null==e?Ir:Math.pow(Ir,e),new uo(this.h,this.s,this.l*e,this.opacity)},rgb:function(){var e=this.h%360+360*(this.h<0),t=isNaN(e)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*t,o=2*n-r;return new no(so(e>=240?e-240:e+120,o,r),so(e,o,r),so(e<120?e+240:e-120,o,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var e=this.opacity;return(1===(e=isNaN(e)?1:Math.max(0,Math.min(1,e)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===e?")":", "+e+")")}}));var lo=function(e){return function(){return e}};function fo(e){return 1===(e=+e)?po:function(t,n){return n-t?function(e,t,n){return e=Math.pow(e,n),t=Math.pow(t,n)-e,n=1/n,function(r){return Math.pow(e+r*t,n)}}(t,n,e):lo(isNaN(t)?n:t)}}function po(e,t){var n=t-e;return n?function(e,t){return function(n){return e+n*t}}(e,n):lo(isNaN(e)?t:e)}var ho=function e(t){var n=fo(t);function r(e,t){var r=n((e=to(e)).r,(t=to(t)).r),o=n(e.g,t.g),i=n(e.b,t.b),a=po(e.opacity,t.opacity);return function(t){return e.r=r(t),e.g=o(t),e.b=i(t),e.opacity=a(t),e+""}}return r.gamma=e,r}(1);function vo(e,t){return e=+e,t=+t,function(n){return e*(1-n)+t*n}}var mo=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,go=new RegExp(mo.source,"g");function bo(e,t){var n,r,o,i=mo.lastIndex=go.lastIndex=0,a=-1,c=[],u=[];for(e+="",t+="";(n=mo.exec(e))&&(r=go.exec(t));)(o=r.index)>i&&(o=t.slice(i,o),c[a]?c[a]+=o:c[++a]=o),(n=n[0])===(r=r[0])?c[a]?c[a]+=r:c[++a]=r:(c[++a]=null,u.push({i:a,x:vo(n,r)})),i=go.lastIndex;return i180?t+=360:t-e>180&&(e+=360),i.push({i:n.push(o(n)+"rotate(",null,r)-2,x:vo(e,t)})):t&&n.push(o(n)+"rotate("+t+r)}(i.rotate,a.rotate,c,u),function(e,t,n,i){e!==t?i.push({i:n.push(o(n)+"skewX(",null,r)-2,x:vo(e,t)}):t&&n.push(o(n)+"skewX("+t+r)}(i.skewX,a.skewX,c,u),function(e,t,n,r,i,a){if(e!==n||t!==r){var c=i.push(o(i)+"scale(",null,",",null,")");a.push({i:c-4,x:vo(e,n)},{i:c-2,x:vo(t,r)})}else 1===n&&1===r||i.push(o(i)+"scale("+n+","+r+")")}(i.scaleX,i.scaleY,a.scaleX,a.scaleY,c,u),i=a=null,function(e){for(var t,n=-1,r=u.length;++n=0&&t._call.call(void 0,e),t=t._next;--Mo}()}finally{Mo=0,function(){var e,t,n=So,r=1/0;for(;n;)n._call?(r>n._time&&(r=n._time),e=n,n=n._next):(t=n._next,n._next=null,n=e?e._next=t:So=t);Co=e,Vo(r)}(),Ao=0}}function Ho(){var e=Io.now(),t=e-Ro;t>1e3&&(Lo-=t,Ro=e)}function Vo(e){Mo||(To&&(To=clearTimeout(To)),e-Ao>24?(e<1/0&&(To=setTimeout(Wo,e-Io.now()-Lo)),No&&(No=clearInterval(No))):(No||(Ro=Io.now(),No=setInterval(Ho,1e3)),Mo=1,Do(Wo)))}function $o(e,t,n){var r=new Fo;return t=null==t?0:+t,r.restart((function(n){r.stop(),e(n+t)}),t,n),r}Fo.prototype=Uo.prototype={constructor:Fo,restart:function(e,t,n){if("function"!==typeof e)throw new TypeError("callback is not a function");n=(null==n?zo():+n)+(null==t?0:+t),this._next||Co===this||(Co?Co._next=this:So=this,Co=this),this._call=e,this._time=n,Vo()},stop:function(){this._call&&(this._call=null,this._time=1/0,Vo())}};var Yo=cn("start","end","cancel","interrupt"),qo=[];function Xo(e,t,n,r,o,i){var a=e.__transition;if(a){if(n in a)return}else e.__transition={};!function(e,t,n){var r,o=e.__transition;function i(e){n.state=1,n.timer.restart(a,n.delay,n.time),n.delay<=e&&a(e-n.delay)}function a(i){var s,l,f,d;if(1!==n.state)return u();for(s in o)if((d=o[s]).name===n.name){if(3===d.state)return $o(a);4===d.state?(d.state=6,d.timer.stop(),d.on.call("interrupt",e,e.__data__,d.index,d.group),delete o[s]):+s0)throw new Error("too late; already scheduled");return n}function Go(e,t){var n=Qo(e,t);if(n.state>3)throw new Error("too late; already running");return n}function Qo(e,t){var n=e.__transition;if(!n||!(n=n[t]))throw new Error("transition not found");return n}function Zo(e,t){var n,r,o,i=e.__transition,a=!0;if(i){for(o in t=null==t?null:t+"",i)(n=i[o]).name===t?(r=n.state>2&&n.state<5,n.state=6,n.timer.stop(),n.on.call(r?"interrupt":"cancel",e,e.__data__,n.index,n.group),delete i[o]):a=!1;a&&delete e.__transition}}function Jo(e,t){var n,r;return function(){var o=Go(this,e),i=o.tween;if(i!==n)for(var a=0,c=(r=n=i).length;a=0&&(e=e.slice(0,t)),!e||"start"===e}))}(t)?Ko:Go;return function(){var a=i(this,e),c=a.on;c!==r&&(o=(r=c).copy()).on(t,n),a.on=o}}var yi=kr.prototype.constructor;function wi(e){return function(){this.style.removeProperty(e)}}function Oi(e,t,n){return function(r){this.style.setProperty(e,t.call(this,r),n)}}function ji(e,t,n){var r,o;function i(){var i=t.apply(this,arguments);return i!==o&&(r=(o=i)&&Oi(e,i,n)),r}return i._value=t,i}function xi(e){return function(t){this.textContent=e.call(this,t)}}function Ei(e){var t,n;function r(){var r=e.apply(this,arguments);return r!==n&&(t=(n=r)&&xi(r)),t}return r._value=e,r}var _i=0;function ki(e,t,n,r){this._groups=e,this._parents=t,this._name=n,this._id=r}function Si(){return++_i}var Ci=kr.prototype;ki.prototype=Object(r.a)({constructor:ki,select:function(e){var t=this._name,n=this._id;"function"!==typeof e&&(e=yn(e));for(var r=this._groups,o=r.length,i=new Array(o),a=0;ar?(r+o)/2:Math.min(0,r)||Math.max(0,o),a>i?(i+a)/2:Math.min(0,i)||Math.max(0,a))}var Hi,Vi,$i,Yi,qi,Xi;!function(e){e.Left="left",e.Top="top",e.Right="right",e.Bottom="bottom"}(Hi||(Hi={})),function(e){e.Arrow="arrow",e.ArrowClosed="arrowclosed"}(Vi||(Vi={})),function(e){e.Lines="lines",e.Dots="dots"}($i||($i={})),function(e){e.Strict="strict",e.Loose="loose"}(Yi||(Yi={})),function(e){e.Bezier="default",e.Straight="straight",e.Step="step",e.SmoothStep="smoothstep"}(qi||(qi={})),function(e){e.Free="free",e.Vertical="vertical",e.Horizontal="horizontal"}(Xi||(Xi={}));var Ki=function(e){return{x:e.x,y:e.y,zoom:e.k}},Gi=function(e){return e.target.closest(".nowheel")},Qi=function(e){var t=e.onMove,n=e.onMoveStart,r=e.onMoveEnd,o=e.zoomOnScroll,i=void 0===o||o,a=e.zoomOnPinch,s=void 0===a||a,l=e.panOnScroll,f=void 0!==l&&l,d=e.panOnScrollSpeed,p=void 0===d?.5:d,h=e.panOnScrollMode,v=void 0===h?Xi.Free:h,m=e.zoomOnDoubleClick,g=void 0===m||m,b=e.selectionKeyPressed,y=e.elementsSelectable,w=e.paneMoveable,O=void 0===w||w,j=e.defaultPosition,x=void 0===j?[0,0]:j,E=e.defaultZoom,_=void 0===E?1:E,k=e.translateExtent,S=e.zoomActivationKeyCode,C=e.preventScrolling,P=void 0===C||C,M=e.children,T=Object(c.useRef)(null),N=Object(c.useRef)({x:0,y:0,zoom:0}),R=Tt(),A=Mt((function(e){return e.d3Zoom})),L=Mt((function(e){return e.d3Selection})),I=Mt((function(e){return e.d3ZoomHandler})),D=Pt((function(e){return e.initD3Zoom})),z=Pt((function(e){return e.updateTransform})),B=Ft(S);return function(e){var t=Pt((function(e){return e.updateSize}));Object(c.useEffect)((function(){var n,r=function(){if(e.current){var n=Dt(e.current);0!==n.height&&0!==n.width||console.warn("The React Flow parent container needs a width and a height to render the graph."),t(n)}};return r(),window.onresize=r,e.current&&(n=new ResizeObserver((function(){return r()}))).observe(e.current),function(){window.onresize=null,n&&e.current&&n.unobserve(e.current)}}),[])}(T),Object(c.useEffect)((function(){if(T.current){var e=R.getState(),t="undefined"!==typeof k?k:e.translateExtent,n=function(){var e,t,n,r=Di,o=zi,i=Wi,a=Fi,c=Ui,u=[0,1/0],s=[[-1/0,-1/0],[1/0,1/0]],l=250,f=Po,d=cn("start","zoom","end"),p=500,h=0,v=10;function m(e){e.property("__zoom",Bi).on("wheel.zoom",x,{passive:!1}).on("mousedown.zoom",E).on("dblclick.zoom",_).filter(c).on("touchstart.zoom",k).on("touchmove.zoom",S).on("touchend.zoom touchcancel.zoom",C).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function g(e,t){return(t=Math.max(u[0],Math.min(u[1],t)))===e.k?e:new Ri(t,e.x,e.y)}function b(e,t,n){var r=t[0]-n[0]*e.k,o=t[1]-n[1]*e.k;return r===e.x&&o===e.y?e:new Ri(e.k,r,o)}function y(e){return[(+e[0][0]+ +e[1][0])/2,(+e[0][1]+ +e[1][1])/2]}function w(e,t,n,r){e.on("start.zoom",(function(){O(this,arguments).event(r).start()})).on("interrupt.zoom end.zoom",(function(){O(this,arguments).event(r).end()})).tween("zoom",(function(){var e=this,i=arguments,a=O(e,i).event(r),c=o.apply(e,i),u=null==n?y(c):"function"===typeof n?n.apply(e,i):n,s=Math.max(c[1][0]-c[0][0],c[1][1]-c[0][1]),l=e.__zoom,d="function"===typeof t?t.apply(e,i):t,p=f(l.invert(u).concat(s/l.k),d.invert(u).concat(s/d.k));return function(e){if(1===e)e=d;else{var t=p(e),n=s/t[2];e=new Ri(n,u[0]-t[0]*n,u[1]-t[1]*n)}a.zoom(null,e)}}))}function O(e,t,n){return!n&&e.__zooming||new j(e,t)}function j(e,t){this.that=e,this.args=t,this.active=0,this.sourceEvent=null,this.extent=o.apply(e,t),this.taps=0}function x(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),o=1;o1?t-1:0),a=1;ah}u.event(e).zoom("mouse",i(b(u.that.__zoom,u.mouse[0]=Cr(e,c),u.mouse[1]),u.extent,s))}function m(e){l.on("mousemove.zoom mouseup.zoom",null),Nr(e.view,u.moved),Ii(e),u.event(e).end()}}function _(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),a=1;a0?Sr(this).transition().duration(l).call(w,p,u,e):Sr(this).call(m.transform,p,u,e)}}function k(n){for(var o=arguments.length,i=new Array(o>1?o-1:0),a=1;a1?t-1:0),r=1;r1?r-1:0),i=1;i0&&void 0!==arguments[0]?arguments[0]:"transform";if("undefined"===typeof window)return"";var r=null===(e=window.document)||void 0===e||null===(t=e.documentElement)||void 0===t?void 0:t.style;if(!r)return"";if(n in r)return"";for(var o=0;o: Unmounted during event!");return t}var Ca={},Pa={};function Ma(e){return(Ma="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}Object.defineProperty(Pa,"__esModule",{value:!0}),Pa.default=function(){},Object.defineProperty(Ca,"__esModule",{value:!0}),Ca.default=void 0;var Ta=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!==Ma(e)&&"function"!==typeof e)return{default:e};var n=Ba(t);if(n&&n.has(e))return n.get(e);var r={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var a=o?Object.getOwnPropertyDescriptor(e,i):null;a&&(a.get||a.set)?Object.defineProperty(r,i,a):r[i]=e[i]}r.default=e,n&&n.set(e,r);return r}(u.a),Na=za(E.exports),Ra=za(l.a),Aa=ia,La=Ea,Ia=aa,Da=za(Pa);function za(e){return e&&e.__esModule?e:{default:e}}function Ba(e){if("function"!==typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(Ba=function(e){return e?n:t})(e)}function Fa(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!==typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==n)return;var r,o,i=[],a=!0,c=!1;try{for(n=n.call(e);!(a=(r=n.next()).done)&&(i.push(r.value),!t||i.length!==t);a=!0);}catch(u){c=!0,o=u}finally{try{a||null==n.return||n.return()}finally{if(c)throw o}}return i}(e,t)||function(e,t){if(!e)return;if("string"===typeof e)return Ua(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Ua(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Ua(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n not mounted on DragStart!");var r=n.ownerDocument;if(!(e.props.disabled||!(t.target instanceof r.defaultView.Node)||e.props.handle&&!(0,Aa.matchesSelectorAndParentsTo)(t.target,e.props.handle,n)||e.props.cancel&&(0,Aa.matchesSelectorAndParentsTo)(t.target,e.props.cancel,n))){"touchstart"===t.type&&t.preventDefault();var o=(0,Aa.getTouchIdentifier)(t);e.setState({touchIdentifier:o});var i=(0,La.getControlPosition)(t,o,qa(e));if(null!=i){var a=i.x,c=i.y,u=(0,La.createCoreData)(qa(e),a,c);(0,Da.default)("DraggableCore: handleDragStart: %j",u),(0,Da.default)("calling",e.props.onStart),!1!==e.props.onStart(t,u)&&!1!==e.mounted&&(e.props.enableUserSelectHack&&(0,Aa.addUserSelectStyles)(r),e.setState({dragging:!0,lastX:a,lastY:c}),(0,Aa.addEvent)(r,Za.move,e.handleDrag),(0,Aa.addEvent)(r,Za.stop,e.handleDragStop))}}})),Ka(qa(e),"handleDrag",(function(t){var n=(0,La.getControlPosition)(t,e.state.touchIdentifier,qa(e));if(null!=n){var r=n.x,o=n.y;if(Array.isArray(e.props.grid)){var i=r-e.state.lastX,a=o-e.state.lastY,c=Fa((0,La.snapToGrid)(e.props.grid,i,a),2);if(i=c[0],a=c[1],!i&&!a)return;r=e.state.lastX+i,o=e.state.lastY+a}var u=(0,La.createCoreData)(qa(e),r,o);if((0,Da.default)("DraggableCore: handleDrag: %j",u),!1!==e.props.onDrag(t,u)&&!1!==e.mounted)e.setState({lastX:r,lastY:o});else try{e.handleDragStop(new MouseEvent("mouseup"))}catch(l){var s=document.createEvent("MouseEvents");s.initMouseEvent("mouseup",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),e.handleDragStop(s)}}})),Ka(qa(e),"handleDragStop",(function(t){if(e.state.dragging){var n=(0,La.getControlPosition)(t,e.state.touchIdentifier,qa(e));if(null!=n){var r=n.x,o=n.y,i=(0,La.createCoreData)(qa(e),r,o);if(!1===e.props.onStop(t,i)||!1===e.mounted)return!1;var a=e.findDOMNode();a&&e.props.enableUserSelectHack&&(0,Aa.removeUserSelectStyles)(a.ownerDocument),(0,Da.default)("DraggableCore: handleDragStop: %j",i),e.setState({dragging:!1,lastX:NaN,lastY:NaN}),a&&((0,Da.default)("DraggableCore: Removing handlers"),(0,Aa.removeEvent)(a.ownerDocument,Za.move,e.handleDrag),(0,Aa.removeEvent)(a.ownerDocument,Za.stop,e.handleDragStop))}}})),Ka(qa(e),"onMouseDown",(function(t){return Za=Qa,e.handleDragStart(t)})),Ka(qa(e),"onMouseUp",(function(t){return Za=Qa,e.handleDragStop(t)})),Ka(qa(e),"onTouchStart",(function(t){return Za=Ga,e.handleDragStart(t)})),Ka(qa(e),"onTouchEnd",(function(t){return Za=Ga,e.handleDragStop(t)})),e}return t=i,(n=[{key:"componentDidMount",value:function(){this.mounted=!0;var e=this.findDOMNode();e&&(0,Aa.addEvent)(e,Ga.start,this.onTouchStart,{passive:!1})}},{key:"componentWillUnmount",value:function(){this.mounted=!1;var e=this.findDOMNode();if(e){var t=e.ownerDocument;(0,Aa.removeEvent)(t,Qa.move,this.handleDrag),(0,Aa.removeEvent)(t,Ga.move,this.handleDrag),(0,Aa.removeEvent)(t,Qa.stop,this.handleDragStop),(0,Aa.removeEvent)(t,Ga.stop,this.handleDragStop),(0,Aa.removeEvent)(e,Ga.start,this.onTouchStart,{passive:!1}),this.props.enableUserSelectHack&&(0,Aa.removeUserSelectStyles)(t)}}},{key:"findDOMNode",value:function(){var e,t,n;return null!==(e=null===(t=this.props)||void 0===t||null===(n=t.nodeRef)||void 0===n?void 0:n.current)&&void 0!==e?e:Ra.default.findDOMNode(this)}},{key:"render",value:function(){return Ta.cloneElement(Ta.Children.only(this.props.children),{onMouseDown:this.onMouseDown,onMouseUp:this.onMouseUp,onTouchEnd:this.onTouchEnd})}}])&&Ha(t.prototype,n),r&&Ha(t,r),i}(Ta.Component);Ca.default=Ja,Ka(Ja,"displayName","DraggableCore"),Ka(Ja,"propTypes",{allowAnyClick:Na.default.bool,disabled:Na.default.bool,enableUserSelectHack:Na.default.bool,offsetParent:function(e,t){if(e[t]&&1!==e[t].nodeType)throw new Error("Draggable's offsetParent must be a DOM Node.")},grid:Na.default.arrayOf(Na.default.number),handle:Na.default.string,cancel:Na.default.string,nodeRef:Na.default.object,onStart:Na.default.func,onDrag:Na.default.func,onStop:Na.default.func,onMouseDown:Na.default.func,scale:Na.default.number,className:Ia.dontSetMe,style:Ia.dontSetMe,transform:Ia.dontSetMe}),Ka(Ja,"defaultProps",{allowAnyClick:!1,disabled:!1,enableUserSelectHack:!0,onStart:function(){},onDrag:function(){},onStop:function(){},onMouseDown:function(){},scale:1}),function(e){function t(e){return(t="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"DraggableCore",{enumerable:!0,get:function(){return f.default}}),e.default=void 0;var n=function(e,n){if(!n&&e&&e.__esModule)return e;if(null===e||"object"!==t(e)&&"function"!==typeof e)return{default:e};var r=v(n);if(r&&r.has(e))return r.get(e);var o={},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var c=i?Object.getOwnPropertyDescriptor(e,a):null;c&&(c.get||c.set)?Object.defineProperty(o,a,c):o[a]=e[a]}o.default=e,r&&r.set(e,o);return o}(u.a),r=h(E.exports),o=h(l.a),i=h(oa),a=ia,c=Ea,s=aa,f=h(Ca),d=h(Pa),p=["axis","bounds","children","defaultPosition","defaultClassName","defaultClassNameDragging","defaultClassNameDragged","position","positionOffset","scale"];function h(e){return e&&e.__esModule?e:{default:e}}function v(e){if("function"!==typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(v=function(e){return e?n:t})(e)}function m(){return(m=Object.assign||function(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function b(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function y(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n, without drag handlers. This will make this component effectively undraggable. Please attach `onDrag` or `onStop` handlers so you can adjust the `position` of this element."),t}return t=l,u=[{key:"getDerivedStateFromProps",value:function(e,t){var n=e.position,r=t.prevPropsPosition;return!n||r&&n.x===r.x&&n.y===r.y?null:((0,d.default)("Draggable: getDerivedStateFromProps %j",{position:n,prevPropsPosition:r}),{x:n.x,y:n.y,prevPropsPosition:y({},n)})}}],(r=[{key:"componentDidMount",value:function(){"undefined"!==typeof window.SVGElement&&this.findDOMNode()instanceof window.SVGElement&&this.setState({isElementSVG:!0})}},{key:"componentWillUnmount",value:function(){this.setState({dragging:!1})}},{key:"findDOMNode",value:function(){var e,t,n;return null!==(e=null===(t=this.props)||void 0===t||null===(n=t.nodeRef)||void 0===n?void 0:n.current)&&void 0!==e?e:o.default.findDOMNode(this)}},{key:"render",value:function(){var e,t=this.props;t.axis,t.bounds;var r=t.children,o=t.defaultPosition,u=t.defaultClassName,s=t.defaultClassNameDragging,l=t.defaultClassNameDragged,d=t.position,h=t.positionOffset;t.scale;var v=g(t,p),b={},w=null,O=!Boolean(d)||this.state.dragging,j=d||o,x={x:(0,c.canDragX)(this)&&O?this.state.x:j.x,y:(0,c.canDragY)(this)&&O?this.state.y:j.y};this.state.isElementSVG?w=(0,a.createSVGTransform)(x,h):b=(0,a.createCSSTransform)(x,h);var E=(0,i.default)(r.props.className||"",u,(P(e={},s,this.state.dragging),P(e,l,this.state.dragged),e));return n.createElement(f.default,m({},v,{onStart:this.onDragStart,onDrag:this.onDrag,onStop:this.onDragStop}),n.cloneElement(n.Children.only(r),{className:E,style:y(y({},r.props.style),b),transform:w}))}}])&&j(t.prototype,r),u&&j(t,u),l}(n.Component);e.default=M,P(M,"displayName","Draggable"),P(M,"propTypes",y(y({},f.default.propTypes),{},{axis:r.default.oneOf(["both","x","y","none"]),bounds:r.default.oneOfType([r.default.shape({left:r.default.number,right:r.default.number,top:r.default.number,bottom:r.default.number}),r.default.string,r.default.oneOf([!1])]),defaultClassName:r.default.string,defaultClassNameDragging:r.default.string,defaultClassNameDragged:r.default.string,defaultPosition:r.default.shape({x:r.default.number,y:r.default.number}),positionOffset:r.default.shape({x:r.default.oneOfType([r.default.number,r.default.string]),y:r.default.oneOfType([r.default.number,r.default.string])}),position:r.default.shape({x:r.default.number,y:r.default.number}),className:s.dontSetMe,style:s.dontSetMe,transform:s.dontSetMe})),P(M,"defaultProps",y(y({},f.default.defaultProps),{},{axis:"both",bounds:!1,defaultClassName:"react-draggable",defaultClassNameDragging:"react-draggable-dragging",defaultClassNameDragged:"react-draggable-dragged",defaultPosition:{x:0,y:0},scale:1}))}(na);var ec=na.default,tc=na.DraggableCore;ta.exports=ec,ta.exports.default=ec;var nc=ta.exports.DraggableCore=tc,rc=ta.exports;function oc(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function ic(e){for(var t=1;tr?t-f:t+f,p=s?0:Math.abs(o-n);return[d,n2&&void 0!==arguments[2]?arguments[2]:null,r=((null===n||void 0===n?void 0:n.x)||0)+t.__rf.position.x,o=((null===n||void 0===n?void 0:n.y)||0)+t.__rf.position.y,i=(null===n||void 0===n?void 0:n.width)||t.__rf.width,a=(null===n||void 0===n?void 0:n.height)||t.__rf.height;switch(e){case Hi.Top:return{x:r+i/2,y:o};case Hi.Right:return{x:r+i,y:o+a/2};case Hi.Bottom:return{x:r+i/2,y:o+a};case Hi.Left:return{x:r,y:o+a/2}}}function qc(e,t){if(!e)return null;var n=null;return 1!==e.length&&t?t&&(n=e.find((function(e){return e.id===t}))):n=e[0],"undefined"===typeof n?null:n}var Xc=function(e){var t=e.edge,n=e.props,r=e.nodes,o=e.selectedElements,i=e.elementsSelectable,a=e.transform,s=e.width,l=e.height,f=e.onlyRenderVisibleElements,d=e.connectionMode,p=t.sourceHandle||null,h=t.targetHandle||null,v=function(e,t){return t.reduce((function(t,n){return n.id===e.source&&(t.sourceNode=n),n.id===e.target&&(t.targetNode=n),t}),{sourceNode:null,targetNode:null})}(t,r),m=v.sourceNode,g=v.targetNode,b=Object(c.useCallback)((function(e){var r;null===(r=n.onEdgeUpdate)||void 0===r||r.call(n,t,e)}),[t,n.onEdgeUpdate]);if(!m)return console.warn("couldn't create edge for source id: ".concat(t.source,"; edge id: ").concat(t.id)),null;if(!g)return console.warn("couldn't create edge for target id: ".concat(t.target,"; edge id: ").concat(t.id)),null;if(!m.__rf.width||!g.__rf.width)return null;var y=t.type||"default",w=n.edgeTypes[y]||n.edgeTypes.default,O=g.__rf.handleBounds,j=d===Yi.Strict?O.target:O.target||O.source,x=qc(m.__rf.handleBounds.source,p),E=qc(j,h),_=x?x.position:Hi.Bottom,k=E?E.position:Hi.Top;if(!x)return console.warn("couldn't create edge for source handle id: ".concat(p,"; edge id: ").concat(t.id)),null;if(!E)return console.warn("couldn't create edge for target handle id: ".concat(h,"; edge id: ").concat(t.id)),null;var S=function(e,t,n,r,o,i){var a=Yc(n,e,t),c=Yc(i,r,o);return{sourceX:a.x,sourceY:a.y,targetX:c.x,targetY:c.y}}(m,x,_,g,E,k),C=S.sourceX,P=S.sourceY,M=S.targetX,T=S.targetY;if(!(!f||function(e){var t=e.sourcePos,n=e.targetPos,r=e.width,o=e.height,i=e.transform,a={x:Math.min(t.x,n.x),y:Math.min(t.y,n.y),x2:Math.max(t.x,n.x),y2:Math.max(t.y,n.y)};a.x===a.x2&&(a.x2+=1),a.y===a.y2&&(a.y2+=1);var c=Gt({x:(0-i[0])/i[2],y:(0-i[1])/i[2],width:r/i[2],height:o/i[2]}),u=Math.max(0,Math.min(c.x2,a.x2)-Math.max(c.x,a.x)),s=Math.max(0,Math.min(c.y2,a.y2)-Math.max(c.y,a.y));return Math.ceil(u*s)>0}({sourcePos:{x:C,y:P},targetPos:{x:M,y:T},width:s,height:l,transform:a})))return null;var N=(null===o||void 0===o?void 0:o.some((function(e){return Ht(e)&&e.id===t.id})))||!1;return u.a.createElement(w,{key:t.id,id:t.id,className:t.className,type:t.type,data:t.data,onClick:n.onElementClick,selected:N,animated:t.animated,label:t.label,labelStyle:t.labelStyle,labelShowBg:t.labelShowBg,labelBgStyle:t.labelBgStyle,labelBgPadding:t.labelBgPadding,labelBgBorderRadius:t.labelBgBorderRadius,style:t.style,arrowHeadType:t.arrowHeadType,source:t.source,target:t.target,sourceHandleId:p,targetHandleId:h,sourceX:C,sourceY:P,targetX:M,targetY:T,sourcePosition:_,targetPosition:k,elementsSelectable:i,markerEndId:n.markerEndId,isHidden:t.isHidden,onConnectEdge:b,handleEdgeUpdate:"undefined"!==typeof n.onEdgeUpdate,onContextMenu:n.onEdgeContextMenu,onMouseEnter:n.onEdgeMouseEnter,onMouseMove:n.onEdgeMouseMove,onMouseLeave:n.onEdgeMouseLeave,edgeUpdaterRadius:n.edgeUpdaterRadius,onEdgeDoubleClick:n.onEdgeDoubleClick,onEdgeUpdateStart:n.onEdgeUpdateStart,onEdgeUpdateEnd:n.onEdgeUpdateEnd})},Kc=function(e){var t=Mt((function(e){return e.transform})),n=Mt((function(e){return e.nodes})),r=Mt((function(e){return e.edges})),o=Mt((function(e){return e.connectionNodeId})),i=Mt((function(e){return e.connectionHandleId})),a=Mt((function(e){return e.connectionHandleType})),c=Mt((function(e){return e.connectionPosition})),s=Mt((function(e){return e.selectedElements})),l=Mt((function(e){return e.nodesConnectable})),f=Mt((function(e){return e.elementsSelectable})),d=Mt((function(e){return e.width})),p=Mt((function(e){return e.height}));if(!d)return null;var h=e.connectionLineType,v=e.arrowHeadColor,m=e.connectionLineStyle,g=e.connectionLineComponent,b=e.onlyRenderVisibleElements,y="translate(".concat(t[0],",").concat(t[1],") scale(").concat(t[2],")"),w=o&&a;return u.a.createElement("svg",{width:d,height:p,className:"react-flow__edges"},u.a.createElement(Nc,{color:v}),u.a.createElement("g",{transform:y},r.map((function(r){return u.a.createElement(Xc,{key:r.id,edge:r,props:e,nodes:n,selectedElements:s,elementsSelectable:f,transform:t,width:d,height:p,onlyRenderVisibleElements:b})})),w&&u.a.createElement(Mc,{nodes:n,connectionNodeId:o,connectionHandleId:i,connectionHandleType:a,connectionPositionX:c.x,connectionPositionY:c.y,transform:t,connectionLineStyle:m,connectionLineType:h,isConnectable:l,CustomConnectionLineComponent:g})))};Kc.displayName="EdgeRenderer";var Gc=Object(c.memo)(Kc),Qc=.1,Zc={zoomIn:function(){},zoomOut:function(){},zoomTo:function(e){},transform:function(e){},fitView:function(){},setCenter:function(e,t){},fitBounds:function(e){},project:function(e){return e},initialized:!1},Jc=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return e.transition().duration(t)},eu=function(){var e=Tt(),t=Mt((function(e){return e.d3Zoom})),n=Mt((function(e){return e.d3Selection}));return Object(c.useMemo)((function(){return n&&t?{zoomIn:function(e){return t.scaleBy(Jc(n,e),1.2)},zoomOut:function(e){return t.scaleBy(Jc(n,e),1/1.2)},zoomTo:function(e,r){return t.scaleTo(Jc(n,r),e)},transform:function(e){var r=Ai.translate(e.x,e.y).scale(e.zoom);t.transform(Jc(n),r)},fitView:function(){var r,o,i,a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{padding:Qc,includeHiddenNodes:!1,duration:0},c=e.getState(),u=c.nodes,s=c.width,l=c.height,f=c.minZoom,d=c.maxZoom;if(u.length){var p=Zt(a.includeHiddenNodes?u:u.filter((function(e){return!e.isHidden}))),h=on(p,s,l,null!==(r=a.minZoom)&&void 0!==r?r:f,null!==(o=a.maxZoom)&&void 0!==o?o:d,null!==(i=a.padding)&&void 0!==i?i:Qc),v=Lt(h,3),m=v[0],g=v[1],b=v[2],y=Ai.translate(m,g).scale(b);t.transform(Jc(n,a.duration),y)}},setCenter:function(r,o,i,a){var c=e.getState(),u=c.width,s=c.height,l=c.maxZoom,f="undefined"!==typeof i?i:l,d=u/2-r*f,p=s/2-o*f,h=Ai.translate(d,p).scale(f);t.transform(Jc(n,a),h)},fitBounds:function(r){var o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Qc,i=arguments.length>2?arguments[2]:void 0,a=e.getState(),c=a.width,u=a.height,s=a.minZoom,l=a.maxZoom,f=on(r,c,u,s,l,o),d=Lt(f,3),p=d[0],h=d[1],v=d[2],m=Ai.translate(p,h).scale(v);t.transform(Jc(n,i),m)},project:function(t){var n=e.getState(),r=n.transform,o=n.snapToGrid,i=n.snapGrid;return $t(t,r,o,i)},initialized:!0}:Zc}),[t,n])},tu=function(e){var t=e.nodeTypes,n=e.edgeTypes,r=e.onMove,o=e.onMoveStart,i=e.onMoveEnd,a=e.onLoad,s=e.onElementClick,l=e.onNodeDoubleClick,f=e.onEdgeDoubleClick,d=e.onNodeMouseEnter,p=e.onNodeMouseMove,h=e.onNodeMouseLeave,v=e.onNodeContextMenu,m=e.onNodeDragStart,g=e.onNodeDrag,b=e.onNodeDragStop,y=e.onSelectionDragStart,w=e.onSelectionDrag,O=e.onSelectionDragStop,j=e.onSelectionContextMenu,x=e.connectionMode,E=e.connectionLineType,_=e.connectionLineStyle,k=e.connectionLineComponent,S=e.selectionKeyCode,C=e.multiSelectionKeyCode,P=e.zoomActivationKeyCode,M=e.onElementsRemove,T=e.deleteKeyCode,N=e.onConnect,R=e.onConnectStart,A=e.onConnectStop,L=e.onConnectEnd,I=e.snapToGrid,D=e.snapGrid,z=e.onlyRenderVisibleElements,B=e.nodesDraggable,F=e.nodesConnectable,U=e.elementsSelectable,W=e.selectNodesOnDrag,H=e.minZoom,V=e.maxZoom,$=e.defaultZoom,Y=e.defaultPosition,q=e.translateExtent,X=e.preventScrolling,K=e.nodeExtent,G=e.arrowHeadColor,Q=e.markerEndId,Z=e.zoomOnScroll,J=e.zoomOnPinch,ee=e.panOnScroll,te=e.panOnScrollSpeed,ne=e.panOnScrollMode,re=e.zoomOnDoubleClick,oe=e.paneMoveable,ie=e.onPaneClick,ae=e.onPaneScroll,ce=e.onPaneContextMenu,ue=e.onEdgeUpdate,se=e.onEdgeContextMenu,le=e.onEdgeMouseEnter,fe=e.onEdgeMouseMove,de=e.onEdgeMouseLeave,pe=e.edgeUpdaterRadius,he=e.onEdgeUpdateStart,ve=e.onEdgeUpdateEnd,me=Object(c.useRef)(!1),ge=Pt((function(e){return e.setOnConnect})),be=Pt((function(e){return e.setOnConnectStart})),ye=Pt((function(e){return e.setOnConnectStop})),we=Pt((function(e){return e.setOnConnectEnd})),Oe=Pt((function(e){return e.setSnapGrid})),je=Pt((function(e){return e.setSnapToGrid})),xe=Pt((function(e){return e.setNodesDraggable})),Ee=Pt((function(e){return e.setNodesConnectable})),_e=Pt((function(e){return e.setElementsSelectable})),ke=Pt((function(e){return e.setMinZoom})),Se=Pt((function(e){return e.setMaxZoom})),Ce=Pt((function(e){return e.setTranslateExtent})),Pe=Pt((function(e){return e.setNodeExtent})),Me=Pt((function(e){return e.setConnectionMode})),Te=Tt(),Ne=eu(),Re=Ne.zoomIn,Ae=Ne.zoomOut,Le=Ne.zoomTo,Ie=Ne.transform,De=Ne.fitView,ze=Ne.initialized;return Object(c.useEffect)((function(){!me.current&&ze&&(a&&a({fitView:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{padding:.1};return De(e)},zoomIn:Re,zoomOut:Ae,zoomTo:Le,setTransform:Ie,project:Yt(Te),getElements:nn(Te),toObject:rn(Te)}),me.current=!0)}),[a,Re,Ae,Le,Ie,De,ze]),Object(c.useEffect)((function(){N&&ge(N)}),[N]),Object(c.useEffect)((function(){R&&be(R)}),[R]),Object(c.useEffect)((function(){A&&ye(A)}),[A]),Object(c.useEffect)((function(){L&&we(L)}),[L]),Object(c.useEffect)((function(){"undefined"!==typeof I&&je(I)}),[I]),Object(c.useEffect)((function(){"undefined"!==typeof D&&Oe(D)}),[D]),Object(c.useEffect)((function(){"undefined"!==typeof B&&xe(B)}),[B]),Object(c.useEffect)((function(){"undefined"!==typeof F&&Ee(F)}),[F]),Object(c.useEffect)((function(){"undefined"!==typeof U&&_e(U)}),[U]),Object(c.useEffect)((function(){"undefined"!==typeof H&&ke(H)}),[H]),Object(c.useEffect)((function(){"undefined"!==typeof V&&Se(V)}),[V]),Object(c.useEffect)((function(){"undefined"!==typeof q&&Ce(q)}),[q]),Object(c.useEffect)((function(){"undefined"!==typeof K&&Pe(K)}),[K]),Object(c.useEffect)((function(){"undefined"!==typeof x&&Me(x)}),[x]),u.a.createElement(uc,{onPaneClick:ie,onPaneContextMenu:ce,onPaneScroll:ae,onElementsRemove:M,deleteKeyCode:T,selectionKeyCode:S,multiSelectionKeyCode:C,zoomActivationKeyCode:P,elementsSelectable:U,onMove:r,onMoveStart:o,onMoveEnd:i,zoomOnScroll:Z,zoomOnPinch:J,zoomOnDoubleClick:re,panOnScroll:ee,panOnScrollSpeed:te,panOnScrollMode:ne,paneMoveable:oe,defaultPosition:Y,defaultZoom:$,translateExtent:q,onSelectionDragStart:y,onSelectionDrag:w,onSelectionDragStop:O,onSelectionContextMenu:j,preventScrolling:X},u.a.createElement(lc,{nodeTypes:t,onElementClick:s,onNodeDoubleClick:l,onNodeMouseEnter:d,onNodeMouseMove:p,onNodeMouseLeave:h,onNodeContextMenu:v,onNodeDragStop:b,onNodeDrag:g,onNodeDragStart:m,selectNodesOnDrag:W,snapToGrid:I,snapGrid:D,onlyRenderVisibleElements:z}),u.a.createElement(Gc,{edgeTypes:n,onElementClick:s,onEdgeDoubleClick:f,connectionLineType:E,connectionLineStyle:_,connectionLineComponent:k,connectionMode:x,arrowHeadColor:G,markerEndId:Q,onEdgeUpdate:ue,onlyRenderVisibleElements:z,onEdgeContextMenu:se,onEdgeMouseEnter:le,onEdgeMouseMove:fe,onEdgeMouseLeave:de,onEdgeUpdateStart:he,onEdgeUpdateEnd:ve,edgeUpdaterRadius:pe}))};tu.displayName="GraphView";var nu=Object(c.memo)(tu),ru=function(e){var t=e.elements,n=Pt((function(e){return e.setElements}));return Object(c.useEffect)((function(){n(t)}),[t]),null},ou=Object(c.createContext)(null),iu=ou.Provider;ou.Consumer;var au=["type","position","isValidConnection","isConnectable","id","onConnect","children","className"];function cu(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}var uu=function(){return!0},su=Object(c.forwardRef)((function(e,t){var n=e.type,r=void 0===n?"source":n,o=e.position,i=void 0===o?Hi.Top:o,a=e.isValidConnection,s=void 0===a?uu:a,l=e.isConnectable,f=void 0===l||l,v=e.id,m=e.onConnect,g=e.children,b=e.className,y=p(e,au),w=Object(c.useContext)(ou),O=Pt((function(e){return e.setConnectionPosition})),j=Pt((function(e){return e.setConnectionNodeId})),x=Mt((function(e){return e.onConnect})),E=Mt((function(e){return e.onConnectStart})),_=Mt((function(e){return e.onConnectStop})),k=Mt((function(e){return e.onConnectEnd})),S=Mt((function(e){return e.connectionMode})),C=v||null,P="target"===r,M=Object(c.useCallback)((function(e){null===x||void 0===x||x(e),null===m||void 0===m||m(e)}),[x,m]),T=Object(c.useCallback)((function(e){Bc(e,C,w,j,O,M,P,s,S,void 0,void 0,E,_,k)}),[C,w,j,O,M,P,s,S,E,_,k]),N=h(["react-flow__handle","react-flow__handle-".concat(i),"nodrag",b,{source:!P,target:P,connectable:f}]);return u.a.createElement("div",function(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:Mu,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case et:var n=t.payload,r={nextNodes:[],nextEdges:[]},o=n.reduce((function(t,n){if(Vt(n)){var r=e.nodes.find((function(e){return e.id===n.id}));if(r){var o=Su(Su({},r),n);r.position.x===n.position.x&&r.position.y===n.position.y||(o.__rf.position=n.position),"undefined"!==typeof n.type&&n.type!==r.type&&(o.__rf.width=null),t.nextNodes.push(o)}else t.nextNodes.push(qt(n,e.nodeExtent))}else if(Ht(n)){var i=e.edges.find((function(e){return e.id===n.id}));i?t.nextEdges.push(Su(Su({},i),n)):t.nextEdges.push(Xt(n))}return t}),r),i=o.nextNodes,a=o.nextEdges;return Su(Su({},e),{},{nodes:i,edges:a});case tt:var c=e.nodes.map((function(n){var r=t.payload.find((function(e){return e.id===n.id}));if(r){var o=Dt(r.nodeElement);if(o.width&&o.height&&(n.__rf.width!==o.width||n.__rf.height!==o.height||r.forceUpdate)){var i=Eu(r.nodeElement,e.transform[2]);return Su(Su({},n),{},{__rf:Su(Su(Su({},n.__rf),o),{},{handleBounds:i})})}}return n}));return Su(Su({},e),{},{nodes:c});case nt:var u=t.payload,s=u.id,l=u.pos,f=l;if(e.snapToGrid){var d=Lt(e.snapGrid,2),p=d[0],h=d[1];f={x:p*Math.round(l.x/p),y:h*Math.round(l.y/h)}}var v=e.nodes.map((function(e){return e.id===s?Su(Su({},e),{},{__rf:Su(Su({},e.__rf),{},{position:f})}):e}));return Su(Su({},e),{},{nodes:v});case rt:var m=t.payload,g=m.id,b=m.diff,y=m.isDragging,w=e.nodes.map((function(t){var n;if(g===t.id||null!==(n=e.selectedElements)&&void 0!==n&&n.find((function(e){return e.id===t.id}))){var r=Su(Su({},t),{},{__rf:Su(Su({},t.__rf),{},{isDragging:y})});return b&&(r.__rf.position={x:t.__rf.position.x+b.x,y:t.__rf.position.y+b.y}),r}return t}));return Su(Su({},e),{},{nodes:w});case ot:var O=t.payload;return Su(Su({},e),{},{selectionActive:!0,userSelectionRect:{width:0,height:0,startX:O.x,startY:O.y,x:O.x,y:O.y,draw:!0}});case it:var j,x,E=t.payload,_=null!==(j=e.userSelectionRect.startX)&&void 0!==j?j:0,k=null!==(x=e.userSelectionRect.startY)&&void 0!==x?x:0,S=Su(Su({},e.userSelectionRect),{},{x:E.x<_?E.x:e.userSelectionRect.x,y:E.y0?M:null}:{};return Su(Su(Su({},e),N),{},{userSelectionRect:S});case at:var R,A=null===(R=e.selectedElements)||void 0===R?void 0:R.filter((function(e){return Vt(e)&&e.__rf})),L=Su(Su({},e),{},{selectionActive:!1,userSelectionRect:Su(Su({},e.userSelectionRect),{},{draw:!1})});if(A&&0!==A.length){var I=Zt(A);L.selectedNodesBbox=I,L.nodesSelectionActive=!0}else L.selectedElements=null,L.nodesSelectionActive=!1;return L;case ut:var D=t.payload,z=Array.isArray(D)?D:[D],B=!ju(z,e.selectedElements),F=B?z:e.selectedElements;return Su(Su({},e),{},{selectedElements:F});case lt:var U=e.multiSelectionActive,W=e.selectedElements,H=t.payload,V=Array.isArray(H)?H:[H],$=V;U&&($=W?[].concat(At(W),At(V)):V);var Y=!ju($,e.selectedElements),q=Y?$:e.selectedElements;return Su(Su({},e),{},{selectedElements:q});case pt:var X=t.payload,K=X.d3Zoom,G=X.d3Selection,Q=X.d3ZoomHandler,Z=X.transform;return Su(Su({},e),{},{d3Zoom:K,d3Selection:G,d3ZoomHandler:Q,transform:Z});case ht:var J,ee=t.payload;return null===(J=e.d3Zoom)||void 0===J||J.scaleExtent([ee,e.maxZoom]),Su(Su({},e),{},{minZoom:ee});case vt:var te,ne=t.payload;return null===(te=e.d3Zoom)||void 0===te||te.scaleExtent([e.minZoom,ne]),Su(Su({},e),{},{maxZoom:ne});case mt:var re,oe=t.payload;return null===(re=e.d3Zoom)||void 0===re||re.translateExtent(oe),Su(Su({},e),{},{translateExtent:oe});case St:var ie=t.payload;return Su(Su({},e),{},{nodeExtent:ie,nodes:e.nodes.map((function(e){return Su(Su({},e),{},{__rf:Su(Su({},e.__rf),{},{position:Bt(e.__rf.position,ie)})})}))});case Ge:case Qe:case Ze:case Je:case st:case ct:case ft:case dt:case gt:case bt:case yt:case wt:case Ot:case jt:case xt:case Et:case _t:case kt:return Su(Su({},e),t.payload);default:return e}}function Pu(e){return w(Cu,e)}var Mu={width:0,height:0,transform:[0,0,1],nodes:[],edges:[],selectedElements:null,selectedNodesBbox:{x:0,y:0,width:0,height:0},d3Zoom:null,d3Selection:null,d3ZoomHandler:void 0,minZoom:.5,maxZoom:2,translateExtent:[[Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY],[Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY]],nodeExtent:[[Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY],[Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY]],nodesSelectionActive:!1,selectionActive:!1,userSelectionRect:{startX:0,startY:0,x:0,y:0,width:0,height:0,draw:!1},connectionNodeId:null,connectionHandleId:null,connectionHandleType:"source",connectionPosition:{x:0,y:0},connectionMode:Yi.Strict,snapGrid:[15,15],snapToGrid:!1,nodesDraggable:!0,nodesConnectable:!0,elementsSelectable:!0,multiSelectionActive:!1,reactFlowVersion:"9.7.0"},Tu=Pu(Mu),Nu=function(e){var t=e.children,n=Object(c.useContext)(te);return Object(c.useMemo)((function(){var e,t;return null===n||void 0===n||null===(e=n.store)||void 0===e||null===(t=e.getState())||void 0===t?void 0:t.reactFlowVersion}),[n])?u.a.createElement(u.a.Fragment,null,t):u.a.createElement(ce,{store:Tu},t)};function Ru(e,t){void 0===t&&(t={});var n=t.insertAt;if(e&&"undefined"!==typeof document){var r=document.head||document.getElementsByTagName("head")[0],o=document.createElement("style");o.type="text/css","top"===n&&r.firstChild?r.insertBefore(o,r.firstChild):r.appendChild(o),o.styleSheet?o.styleSheet.cssText=e:o.appendChild(document.createTextNode(e))}}Nu.displayName="ReactFlowWrapper";Ru(".react-flow{height:100%;overflow:hidden;position:relative;width:100%}.react-flow__pane,.react-flow__renderer,.react-flow__selectionpane{height:100%;left:0;position:absolute;top:0;width:100%}.react-flow__pane{z-index:1}.react-flow__renderer{z-index:4}.react-flow__selectionpane{z-index:5}.react-flow__edges,.react-flow__selection{left:0;position:absolute;top:0}.react-flow__edges{pointer-events:none;z-index:2}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.inactive{pointer-events:none}@-webkit-keyframes dashdraw{0%{stroke-dashoffset:10}}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edge-path{fill:none}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;-webkit-animation:dashdraw .5s linear infinite;animation:dashdraw .5s linear infinite}.react-flow__connection-path{fill:none}.react-flow__nodes{height:100%;pointer-events:none;width:100%;z-index:3}.react-flow__node,.react-flow__nodes{position:absolute;transform-origin:0 0}.react-flow__node{pointer-events:all;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.react-flow__nodesselection{height:100%;left:0;pointer-events:none;position:absolute;top:0;transform-origin:left top;width:100%;z-index:3}.react-flow__nodesselection-rect{cursor:-webkit-grab;cursor:grab;pointer-events:all;position:absolute}.react-flow__handle{pointer-events:none}.react-flow__handle.connectable{pointer-events:all}.react-flow__handle-bottom{bottom:-4px;left:50%;top:auto;transform:translate(-50%)}.react-flow__handle-top{left:50%;top:-4px;transform:translate(-50%)}.react-flow__handle-left{left:-4px;top:50%;transform:translateY(-50%)}.react-flow__handle-right{right:-4px;top:50%;transform:translateY(-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__background{height:100%;left:0;position:absolute;top:0;width:100%}.react-flow__controls{bottom:10px;left:10px;position:absolute;z-index:5}.react-flow__controls-button{border:none;height:24px;width:24px}.react-flow__controls-button svg{width:100%}.react-flow__minimap{bottom:10px;position:absolute;right:10px;z-index:5}");Ru(".react-flow__selection{background:rgba(0,89,220,.08);border:1px dotted rgba(0,89,220,.8)}.react-flow__edge.selected .react-flow__edge-path{stroke:#555}.react-flow__edge.animated path{stroke-dasharray:5;-webkit-animation:dashdraw .5s linear infinite;animation:dashdraw .5s linear infinite}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-path{stroke:#b1b1b7;stroke-width:1}.react-flow__edge-text{font-size:10px}.react-flow__edge-textbg{fill:#fff}.react-flow__connection-path{stroke:#b1b1b7;stroke-width:1}.react-flow__node{cursor:-webkit-grab;cursor:grab}.react-flow__node-default,.react-flow__node-input,.react-flow__node-output{border-radius:3px;border-style:solid;border-width:1px;color:#222;font-size:12px;padding:10px;text-align:center;width:150px}.react-flow__node-default.selectable:hover,.react-flow__node-input.selectable:hover,.react-flow__node-output.selectable:hover{box-shadow:0 1px 4px 1px rgba(0,0,0,.08)}.react-flow__node-input{background:#fff;border-color:#0041d0}.react-flow__node-input.selected,.react-flow__node-input.selected:hover{box-shadow:0 0 0 .5px #0041d0}.react-flow__node-input .react-flow__handle{background:#0041d0}.react-flow__node-default{background:#fff;border-color:#1a192b}.react-flow__node-default.selected,.react-flow__node-default.selected:hover{box-shadow:0 0 0 .5px #1a192b}.react-flow__node-default .react-flow__handle{background:#1a192b}.react-flow__node-output{background:#fff;border-color:#ff0072}.react-flow__node-output.selected,.react-flow__node-output.selected:hover{box-shadow:0 0 0 .5px #ff0072}.react-flow__node-output .react-flow__handle{background:#ff0072}.react-flow__nodesselection-rect{background:rgba(0,89,220,.08);border:1px dotted rgba(0,89,220,.8)}.react-flow__handle{background:#555;border:1px solid #fff;border-radius:100%;height:6px;position:absolute;width:6px}.react-flow__handle.connectable{cursor:crosshair}.react-flow__minimap{background-color:#fff}.react-flow__controls{box-shadow:0 0 2px 1px rgba(0,0,0,.08)}.react-flow__controls-button{align-items:center;background:#fefefe;border-bottom:1px solid #eee;box-sizing:content-box;cursor:pointer;display:flex;height:16px;justify-content:center;padding:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:16px}.react-flow__controls-button svg{max-height:12px;max-width:12px}.react-flow__controls-button:hover{background:#f4f4f4}");var Au=["elements","className","nodeTypes","edgeTypes","onElementClick","onLoad","onMove","onMoveStart","onMoveEnd","onElementsRemove","onConnect","onConnectStart","onConnectStop","onConnectEnd","onNodeMouseEnter","onNodeMouseMove","onNodeMouseLeave","onNodeContextMenu","onNodeDoubleClick","onNodeDragStart","onNodeDrag","onNodeDragStop","onSelectionChange","onSelectionDragStart","onSelectionDrag","onSelectionDragStop","onSelectionContextMenu","connectionMode","connectionLineType","connectionLineStyle","connectionLineComponent","deleteKeyCode","selectionKeyCode","multiSelectionKeyCode","zoomActivationKeyCode","snapToGrid","snapGrid","onlyRenderVisibleElements","selectNodesOnDrag","nodesDraggable","nodesConnectable","elementsSelectable","minZoom","maxZoom","defaultZoom","defaultPosition","translateExtent","preventScrolling","nodeExtent","arrowHeadColor","markerEndId","zoomOnScroll","zoomOnPinch","panOnScroll","panOnScrollSpeed","panOnScrollMode","zoomOnDoubleClick","paneMoveable","onPaneClick","onPaneScroll","onPaneContextMenu","children","onEdgeUpdate","onEdgeContextMenu","onEdgeDoubleClick","onEdgeMouseEnter","onEdgeMouseMove","onEdgeMouseLeave","onEdgeUpdateStart","onEdgeUpdateEnd","edgeUpdaterRadius","nodeTypesId","edgeTypesId"];function Lu(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Iu(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:{},n=null==t||null==(e=t.keys)?void 0:e.reduce((function(e,n){return e[t.up(n)]={},e}),{});return n||{}}function c(e,t){return e.reduce((function(e,t){var n=e[t];return(!n||0===Object.keys(n).length)&&delete e[t],e}),t)}},function(e,t,n){"use strict";function r(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}n.d(t,"a",(function(){return r}))},function(e,t,n){"use strict";n.d(t,"a",(function(){return h})),n.d(t,"b",(function(){return l})),n.d(t,"c",(function(){return d})),n.d(t,"d",(function(){return c})),n.d(t,"e",(function(){return s}));var r=n(0),o=n(179);n(111),n(178);var i=n(54),a=n(68),c={}.hasOwnProperty,u=Object(r.createContext)("undefined"!==typeof HTMLElement?Object(o.a)({key:"css"}):null);u.Provider;var s=function(e){return Object(r.forwardRef)((function(t,n){var o=Object(r.useContext)(u);return e(t,o,n)}))},l=Object(r.createContext)({});var f="__EMOTION_TYPE_PLEASE_DO_NOT_USE__",d=function(e,t){var n={};for(var r in t)c.call(t,r)&&(n[r]=t[r]);return n[f]=e,n},p=function(){return null},h=s((function(e,t,n){var o=e.css;"string"===typeof o&&void 0!==t.registered[o]&&(o=t.registered[o]);var u=e[f],s=[o],d="";"string"===typeof e.className?d=Object(i.a)(t.registered,s,e.className):null!=e.className&&(d=e.className+" ");var h=Object(a.a)(s,void 0,Object(r.useContext)(l));Object(i.b)(t,h,"string"===typeof u);d+=t.key+"-"+h.name;var v={};for(var m in e)c.call(e,m)&&"css"!==m&&m!==f&&(v[m]=e[m]);v.ref=n,v.className=d;var g=Object(r.createElement)(u,v),b=Object(r.createElement)(p,null);return Object(r.createElement)(r.Fragment,null,b,g)}))},function(e,t,n){"use strict";function r(e){return(r=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}n.d(t,"a",(function(){return r}))},function(e,t,n){"use strict";n.d(t,"e",(function(){return I})),n.d(t,"d",(function(){return D})),n.d(t,"b",(function(){return z})),n.d(t,"a",(function(){return B}));var r=n(12),o=n(3),i=n(4),a=n(2),c=n(153),u=n(0),s=n(6),l=n(155),f=n(286),d=n(552),p=n(553),h=n(121),v=n(1),m=["onChange","maxRows","minRows","style","value"];function g(e,t){return parseInt(e[t],10)||0}var b={visibility:"hidden",position:"absolute",overflow:"hidden",height:0,top:0,left:0,transform:"translateZ(0)"},y=u.forwardRef((function(e,t){var n=e.onChange,o=e.maxRows,c=e.minRows,s=void 0===c?1:c,l=e.style,y=e.value,w=Object(i.a)(e,m),O=u.useRef(null!=y).current,j=u.useRef(null),x=Object(f.a)(t,j),E=u.useRef(null),_=u.useRef(0),k=u.useState({}),S=Object(r.a)(k,2),C=S[0],P=S[1],M=u.useCallback((function(){var t=j.current,n=Object(d.a)(t).getComputedStyle(t);if("0px"!==n.width){var r=E.current;r.style.width=n.width,r.value=t.value||e.placeholder||"x","\n"===r.value.slice(-1)&&(r.value+=" ");var i=n["box-sizing"],a=g(n,"padding-bottom")+g(n,"padding-top"),c=g(n,"border-bottom-width")+g(n,"border-top-width"),u=r.scrollHeight;r.value="x";var l=r.scrollHeight,f=u;s&&(f=Math.max(Number(s)*l,f)),o&&(f=Math.min(Number(o)*l,f));var p=(f=Math.max(f,l))+("border-box"===i?a+c:0),h=Math.abs(f-u)<=1;P((function(e){return _.current<20&&(p>0&&Math.abs((e.outerHeightStyle||0)-p)>1||e.overflow!==h)?(_.current+=1,{overflow:h,outerHeightStyle:p}):e}))}}),[o,s,e.placeholder]);u.useEffect((function(){var e,t=Object(p.a)((function(){_.current=0,M()})),n=Object(d.a)(j.current);return n.addEventListener("resize",t),"undefined"!==typeof ResizeObserver&&(e=new ResizeObserver(t)).observe(j.current),function(){t.clear(),n.removeEventListener("resize",t),e&&e.disconnect()}}),[M]),Object(h.a)((function(){M()})),u.useEffect((function(){_.current=0}),[y]);return Object(v.jsxs)(u.Fragment,{children:[Object(v.jsx)("textarea",Object(a.a)({value:y,onChange:function(e){_.current=0,O||M(),n&&n(e)},ref:x,rows:s,style:Object(a.a)({height:C.outerHeightStyle,overflow:C.overflow?"hidden":null},l)},w)),Object(v.jsx)("textarea",{"aria-hidden":!0,className:e.className,readOnly:!0,ref:E,tabIndex:-1,style:Object(a.a)({},b,l,{padding:0})})]})})),w=n(96),O=n(149),j=n(97),x=n(75),E=n(5),_=n(10),k=n(8),S=n(20),C=n(98),P=n(550),M=n(150),T=n(84),N=n(104);function R(e){return Object(T.a)("MuiInputBase",e)}var A=Object(N.a)("MuiInputBase",["root","formControl","focused","disabled","adornedStart","adornedEnd","error","sizeSmall","multiline","colorSecondary","fullWidth","hiddenLabel","input","inputSizeSmall","inputMultiline","inputTypeSearch","inputAdornedStart","inputAdornedEnd","inputHiddenLabel"]),L=["aria-describedby","autoComplete","autoFocus","className","color","components","componentsProps","defaultValue","disabled","endAdornment","error","fullWidth","id","inputComponent","inputProps","inputRef","margin","maxRows","minRows","multiline","name","onBlur","onChange","onClick","onFocus","onKeyDown","onKeyUp","placeholder","readOnly","renderSuffix","rows","size","startAdornment","type","value"],I=function(e,t){var n=e.ownerState;return[t.root,n.formControl&&t.formControl,n.startAdornment&&t.adornedStart,n.endAdornment&&t.adornedEnd,n.error&&t.error,"small"===n.size&&t.sizeSmall,n.multiline&&t.multiline,n.color&&t["color".concat(Object(k.a)(n.color))],n.fullWidth&&t.fullWidth,n.hiddenLabel&&t.hiddenLabel]},D=function(e,t){var n=e.ownerState;return[t.input,"small"===n.size&&t.inputSizeSmall,n.multiline&&t.inputMultiline,"search"===n.type&&t.inputTypeSearch,n.startAdornment&&t.inputAdornedStart,n.endAdornment&&t.inputAdornedEnd,n.hiddenLabel&&t.inputHiddenLabel]},z=Object(E.a)("div",{name:"MuiInputBase",slot:"Root",overridesResolver:I})((function(e){var t=e.theme,n=e.ownerState;return Object(a.a)({},t.typography.body1,Object(o.a)({color:t.palette.text.primary,lineHeight:"1.4375em",boxSizing:"border-box",position:"relative",cursor:"text",display:"inline-flex",alignItems:"center"},"&.".concat(A.disabled),{color:t.palette.text.disabled,cursor:"default"}),n.multiline&&Object(a.a)({padding:"4px 0 5px"},"small"===n.size&&{paddingTop:1}),n.fullWidth&&{width:"100%"})})),B=Object(E.a)("input",{name:"MuiInputBase",slot:"Input",overridesResolver:D})((function(e){var t,n=e.theme,r=e.ownerState,i="light"===n.palette.mode,c={color:"currentColor",opacity:i?.42:.5,transition:n.transitions.create("opacity",{duration:n.transitions.duration.shorter})},u={opacity:"0 !important"},s={opacity:i?.42:.5};return Object(a.a)((t={font:"inherit",letterSpacing:"inherit",color:"currentColor",padding:"4px 0 5px",border:0,boxSizing:"content-box",background:"none",height:"1.4375em",margin:0,WebkitTapHighlightColor:"transparent",display:"block",minWidth:0,width:"100%",animationName:"mui-auto-fill-cancel",animationDuration:"10ms","&::-webkit-input-placeholder":c,"&::-moz-placeholder":c,"&:-ms-input-placeholder":c,"&::-ms-input-placeholder":c,"&:focus":{outline:0},"&:invalid":{boxShadow:"none"},"&::-webkit-search-decoration":{WebkitAppearance:"none"}},Object(o.a)(t,"label[data-shrink=false] + .".concat(A.formControl," &"),{"&::-webkit-input-placeholder":u,"&::-moz-placeholder":u,"&:-ms-input-placeholder":u,"&::-ms-input-placeholder":u,"&:focus::-webkit-input-placeholder":s,"&:focus::-moz-placeholder":s,"&:focus:-ms-input-placeholder":s,"&:focus::-ms-input-placeholder":s}),Object(o.a)(t,"&.".concat(A.disabled),{opacity:1,WebkitTextFillColor:n.palette.text.disabled}),Object(o.a)(t,"&:-webkit-autofill",{animationDuration:"5000s",animationName:"mui-auto-fill"}),t),"small"===r.size&&{paddingTop:1},r.multiline&&{height:"auto",resize:"none",padding:0,paddingTop:0},"search"===r.type&&{MozAppearance:"textfield"})})),F=Object(v.jsx)(P.a,{styles:{"@keyframes mui-auto-fill":{from:{display:"block"}},"@keyframes mui-auto-fill-cancel":{from:{display:"block"}}}}),U=u.forwardRef((function(e,t){var n=Object(_.a)({props:e,name:"MuiInputBase"}),o=n["aria-describedby"],f=n.autoComplete,d=n.autoFocus,p=n.className,h=n.components,m=void 0===h?{}:h,g=n.componentsProps,b=void 0===g?{}:g,E=n.defaultValue,P=n.disabled,T=n.endAdornment,N=n.fullWidth,A=void 0!==N&&N,I=n.id,D=n.inputComponent,U=void 0===D?"input":D,W=n.inputProps,H=void 0===W?{}:W,V=n.inputRef,$=n.maxRows,Y=n.minRows,q=n.multiline,X=void 0!==q&&q,K=n.name,G=n.onBlur,Q=n.onChange,Z=n.onClick,J=n.onFocus,ee=n.onKeyDown,te=n.onKeyUp,ne=n.placeholder,re=n.readOnly,oe=n.renderSuffix,ie=n.rows,ae=n.startAdornment,ce=n.type,ue=void 0===ce?"text":ce,se=n.value,le=Object(i.a)(n,L),fe=null!=H.value?H.value:se,de=u.useRef(null!=fe).current,pe=u.useRef(),he=u.useCallback((function(e){0}),[]),ve=Object(S.a)(H.ref,he),me=Object(S.a)(V,ve),ge=Object(S.a)(pe,me),be=u.useState(!1),ye=Object(r.a)(be,2),we=ye[0],Oe=ye[1],je=Object(x.a)();var xe=Object(O.a)({props:n,muiFormControl:je,states:["color","disabled","error","hiddenLabel","size","required","filled"]});xe.focused=je?je.focused:we,u.useEffect((function(){!je&&P&&we&&(Oe(!1),G&&G())}),[je,P,we,G]);var Ee=je&&je.onFilled,_e=je&&je.onEmpty,ke=u.useCallback((function(e){Object(M.a)(e)?Ee&&Ee():_e&&_e()}),[Ee,_e]);Object(C.a)((function(){de&&ke({value:fe})}),[fe,ke,de]);u.useEffect((function(){ke(pe.current)}),[]);var Se=U,Ce=H;X&&"input"===Se&&(Ce=ie?Object(a.a)({type:void 0,minRows:ie,maxRows:ie},Ce):Object(a.a)({type:void 0,maxRows:$,minRows:Y},Ce),Se=y);u.useEffect((function(){je&&je.setAdornedStart(Boolean(ae))}),[je,ae]);var Pe=Object(a.a)({},n,{color:xe.color||"primary",disabled:xe.disabled,endAdornment:T,error:xe.error,focused:xe.focused,formControl:je,fullWidth:A,hiddenLabel:xe.hiddenLabel,multiline:X,size:xe.size,startAdornment:ae,type:ue}),Me=function(e){var t=e.classes,n=e.color,r=e.disabled,o=e.error,i=e.endAdornment,a=e.focused,c=e.formControl,u=e.fullWidth,s=e.hiddenLabel,f=e.multiline,d=e.size,p=e.startAdornment,h=e.type,v={root:["root","color".concat(Object(k.a)(n)),r&&"disabled",o&&"error",u&&"fullWidth",a&&"focused",c&&"formControl","small"===d&&"sizeSmall",f&&"multiline",p&&"adornedStart",i&&"adornedEnd",s&&"hiddenLabel"],input:["input",r&&"disabled","search"===h&&"inputTypeSearch",f&&"inputMultiline","small"===d&&"inputSizeSmall",s&&"inputHiddenLabel",p&&"inputAdornedStart",i&&"inputAdornedEnd"]};return Object(l.a)(v,R,t)}(Pe),Te=m.Root||z,Ne=b.root||{},Re=m.Input||B;return Ce=Object(a.a)({},Ce,b.input),Object(v.jsxs)(u.Fragment,{children:[F,Object(v.jsxs)(Te,Object(a.a)({},Ne,!Object(w.a)(Te)&&{ownerState:Object(a.a)({},Pe,Ne.ownerState)},{ref:t,onClick:function(e){pe.current&&e.currentTarget===e.target&&pe.current.focus(),Z&&Z(e)}},le,{className:Object(s.a)(Me.root,Ne.className,p),children:[ae,Object(v.jsx)(j.a.Provider,{value:null,children:Object(v.jsx)(Re,Object(a.a)({ownerState:Pe,"aria-invalid":xe.error,"aria-describedby":o,autoComplete:f,autoFocus:d,defaultValue:E,disabled:xe.disabled,id:I,onAnimationStart:function(e){ke("mui-auto-fill-cancel"===e.animationName?pe.current:{value:"x"})},name:K,placeholder:ne,readOnly:re,required:xe.required,rows:ie,value:fe,onKeyDown:ee,onKeyUp:te,type:ue},Ce,!Object(w.a)(Re)&&{as:Se,ownerState:Object(a.a)({},Pe,Ce.ownerState)},{ref:ge,className:Object(s.a)(Me.input,Ce.className),onBlur:function(e){G&&G(e),H.onBlur&&H.onBlur(e),je&&je.onBlur?je.onBlur(e):Oe(!1)},onChange:function(e){if(!de){var t=e.target||pe.current;if(null==t)throw new Error(Object(c.a)(1));ke({value:t.value})}for(var n=arguments.length,r=new Array(n>1?n-1:0),o=1;o2){if(!s[e])return[e];e=s[e]}var t=e.split(""),n=Object(r.a)(t,2),o=n[0],i=n[1],a=c[o],l=u[i]||"";return Array.isArray(l)?l.map((function(e){return a+e})):[a+l]})),f=["m","mt","mr","mb","ml","mx","my","margin","marginTop","marginRight","marginBottom","marginLeft","marginX","marginY","marginInline","marginInlineStart","marginInlineEnd","marginBlock","marginBlockStart","marginBlockEnd"],d=["p","pt","pr","pb","pl","px","py","padding","paddingTop","paddingRight","paddingBottom","paddingLeft","paddingX","paddingY","paddingInline","paddingInlineStart","paddingInlineEnd","paddingBlock","paddingBlockStart","paddingBlockEnd"],p=[].concat(f,d);function h(e,t,n,r){var o=Object(i.b)(e,t)||n;return"number"===typeof o?function(e){return"string"===typeof e?e:o*e}:Array.isArray(o)?function(e){return"string"===typeof e?e:o[e]}:"function"===typeof o?o:function(){}}function v(e){return h(e,"spacing",8)}function m(e,t){if("string"===typeof t||null==t)return t;var n=e(Math.abs(t));return t>=0?n:"number"===typeof n?-n:"-".concat(n)}function g(e,t,n,r){if(-1===t.indexOf(n))return null;var i=function(e,t){return function(n){return e.reduce((function(e,r){return e[r]=m(t,n),e}),{})}}(l(n),r),a=e[n];return Object(o.b)(e,a,i)}function b(e,t){var n=v(e.theme);return Object.keys(e).map((function(r){return g(e,t,r,n)})).reduce(a.a,{})}function y(e){return b(e,f)}function w(e){return b(e,d)}function O(e){return b(e,p)}y.propTypes={},y.filterProps=f,w.propTypes={},w.filterProps=d,O.propTypes={},O.filterProps=p;t.c=O},function(e,t,n){"use strict";var r=n(25),o=n(51).Graph;function i(e,t,n,o){var i;do{i=r.uniqueId(o)}while(e.hasNode(i));return n.dummy=t,e.setNode(i,n),i}function a(e){return r.max(r.map(e.nodes(),(function(t){var n=e.node(t).rank;if(!r.isUndefined(n))return n})))}e.exports={addDummyNode:i,simplify:function(e){var t=(new o).setGraph(e.graph());return r.forEach(e.nodes(),(function(n){t.setNode(n,e.node(n))})),r.forEach(e.edges(),(function(n){var r=t.edge(n.v,n.w)||{weight:0,minlen:1},o=e.edge(n);t.setEdge(n.v,n.w,{weight:r.weight+o.weight,minlen:Math.max(r.minlen,o.minlen)})})),t},asNonCompoundGraph:function(e){var t=new o({multigraph:e.isMultigraph()}).setGraph(e.graph());return r.forEach(e.nodes(),(function(n){e.children(n).length||t.setNode(n,e.node(n))})),r.forEach(e.edges(),(function(n){t.setEdge(n,e.edge(n))})),t},successorWeights:function(e){var t=r.map(e.nodes(),(function(t){var n={};return r.forEach(e.outEdges(t),(function(t){n[t.w]=(n[t.w]||0)+e.edge(t).weight})),n}));return r.zipObject(e.nodes(),t)},predecessorWeights:function(e){var t=r.map(e.nodes(),(function(t){var n={};return r.forEach(e.inEdges(t),(function(t){n[t.v]=(n[t.v]||0)+e.edge(t).weight})),n}));return r.zipObject(e.nodes(),t)},intersectRect:function(e,t){var n,r,o=e.x,i=e.y,a=t.x-o,c=t.y-i,u=e.width/2,s=e.height/2;if(!a&&!c)throw new Error("Not possible to find intersection inside of the rectangle");Math.abs(c)*u>Math.abs(a)*s?(c<0&&(s=-s),n=s*a/c,r=s):(a<0&&(u=-u),n=u,r=u*c/a);return{x:o+n,y:i+r}},buildLayerMatrix:function(e){var t=r.map(r.range(a(e)+1),(function(){return[]}));return r.forEach(e.nodes(),(function(n){var o=e.node(n),i=o.rank;r.isUndefined(i)||(t[i][o.order]=n)})),t},normalizeRanks:function(e){var t=r.min(r.map(e.nodes(),(function(t){return e.node(t).rank})));r.forEach(e.nodes(),(function(n){var o=e.node(n);r.has(o,"rank")&&(o.rank-=t)}))},removeEmptyRanks:function(e){var t=r.min(r.map(e.nodes(),(function(t){return e.node(t).rank}))),n=[];r.forEach(e.nodes(),(function(r){var o=e.node(r).rank-t;n[o]||(n[o]=[]),n[o].push(r)}));var o=0,i=e.graph().nodeRankFactor;r.forEach(n,(function(t,n){r.isUndefined(t)&&n%i!==0?--o:o&&r.forEach(t,(function(t){e.node(t).rank+=o}))}))},addBorderNode:function(e,t,n,r){var o={width:0,height:0};arguments.length>=4&&(o.rank=n,o.order=r);return i(e,"border",o,t)},maxRank:a,partition:function(e,t){var n={lhs:[],rhs:[]};return r.forEach(e,(function(e){t(e)?n.lhs.push(e):n.rhs.push(e)})),n},time:function(e,t){var n=r.now();try{return t()}finally{console.log(e+" time: "+(r.now()-n)+"ms")}},notime:function(e,t){return t()}}},function(e,t,n){"use strict";!function e(){if("undefined"!==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"===typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(302)},function(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:["all"],o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},a=o.duration,c=void 0===a?n.standard:a,s=o.easing,l=void 0===s?t.easeInOut:s,f=o.delay,d=void 0===f?0:f;Object(r.a)(o,i);return(Array.isArray(e)?e:[e]).map((function(e){return"".concat(e," ").concat("string"===typeof c?c:u(c)," ").concat(l," ").concat("string"===typeof d?d:u(d))})).join(",")}},e,{easing:t,duration:n})}},,function(e,t,n){var r;try{r={clone:n(336),constant:n(171),each:n(221),filter:n(224),has:n(235),isArray:n(31),isEmpty:n(412),isFunction:n(105),isUndefined:n(236),keys:n(69),map:n(237),reduce:n(239),size:n(415),transform:n(421),union:n(422),values:n(244)}}catch(o){}r||(r=window._),e.exports=r},function(e,t){e.exports=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}},function(e,t){function n(e){if(e)return function(e){for(var t in n.prototype)e[t]=n.prototype[t];return e}(e)}t.Emitter=n,n.prototype.on=n.prototype.addEventListener=function(e,t){return this._callbacks=this._callbacks||{},(this._callbacks["$"+e]=this._callbacks["$"+e]||[]).push(t),this},n.prototype.once=function(e,t){function n(){this.off(e,n),t.apply(this,arguments)}return n.fn=t,this.on(e,n),this},n.prototype.off=n.prototype.removeListener=n.prototype.removeAllListeners=n.prototype.removeEventListener=function(e,t){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n,r=this._callbacks["$"+e];if(!r)return this;if(1==arguments.length)return delete this._callbacks["$"+e],this;for(var o=0;o1?t-1:0),r=1;r>4,l[u++]=(15&r)<<4|o>>2,l[u++]=(3&o)<<6|63&i;return s}(e);return v(n,t)}return{base64:!0,data:e}},v=function(e,t){switch(t){case"blob":return e instanceof ArrayBuffer?new Blob([e]):e;case"arraybuffer":default:return e}},m=function(e,t){if("string"!==typeof e)return{type:"message",data:v(e,t)};var n=e.charAt(0);return"b"===n?{type:"message",data:h(e.substring(1),t)}:o[n]?e.length>1?{type:o[n],data:e.substring(1)}:{type:o[n]}:i},g=String.fromCharCode(30),b=function(e,t){var n=e.length,r=new Array(n),o=0;e.forEach((function(e,i){s(e,!1,(function(e){r[i]=e,++o===n&&t(r.join(g))}))}))},y=function(e,t){for(var n=e.split(g),r=[],o=0;o=4;++r,o-=4)t=1540483477*(65535&(t=255&e.charCodeAt(r)|(255&e.charCodeAt(++r))<<8|(255&e.charCodeAt(++r))<<16|(255&e.charCodeAt(++r))<<24))+(59797*(t>>>16)<<16),n=1540483477*(65535&(t^=t>>>24))+(59797*(t>>>16)<<16)^1540483477*(65535&n)+(59797*(n>>>16)<<16);switch(o){case 3:n^=(255&e.charCodeAt(r+2))<<16;case 2:n^=(255&e.charCodeAt(r+1))<<8;case 1:n=1540483477*(65535&(n^=255&e.charCodeAt(r)))+(59797*(n>>>16)<<16)}return(((n=1540483477*(65535&(n^=n>>>13))+(59797*(n>>>16)<<16))^n>>>15)>>>0).toString(36)},o={animationIterationCount:1,borderImageOutset:1,borderImageSlice:1,borderImageWidth:1,boxFlex:1,boxFlexGroup:1,boxOrdinalGroup:1,columnCount:1,columns:1,flex:1,flexGrow:1,flexPositive:1,flexShrink:1,flexNegative:1,flexOrder:1,gridRow:1,gridRowEnd:1,gridRowSpan:1,gridRowStart:1,gridColumn:1,gridColumnEnd:1,gridColumnSpan:1,gridColumnStart:1,msGridRow:1,msGridRowSpan:1,msGridColumn:1,msGridColumnSpan:1,fontWeight:1,lineHeight:1,opacity:1,order:1,orphans:1,tabSize:1,widows:1,zIndex:1,zoom:1,WebkitLineClamp:1,fillOpacity:1,floodOpacity:1,stopOpacity:1,strokeDasharray:1,strokeDashoffset:1,strokeMiterlimit:1,strokeOpacity:1,strokeWidth:1},i=n(110),a=/[A-Z]|^ms/g,c=/_EMO_([^_]+?)_([^]*?)_EMO_/g,u=function(e){return 45===e.charCodeAt(1)},s=function(e){return null!=e&&"boolean"!==typeof e},l=Object(i.a)((function(e){return u(e)?e:e.replace(a,"-$&").toLowerCase()})),f=function(e,t){switch(e){case"animation":case"animationName":if("string"===typeof t)return t.replace(c,(function(e,t,n){return p={name:t,styles:n,next:p},t}))}return 1===o[e]||u(e)||"number"!==typeof t||0===t?t:t+"px"};function d(e,t,n){if(null==n)return"";if(void 0!==n.__emotion_styles)return n;switch(typeof n){case"boolean":return"";case"object":if(1===n.anim)return p={name:n.name,styles:n.styles,next:p},n.name;if(void 0!==n.styles){var r=n.next;if(void 0!==r)for(;void 0!==r;)p={name:r.name,styles:r.styles,next:p},r=r.next;return n.styles+";"}return function(e,t,n){var r="";if(Array.isArray(n))for(var o=0;o=0||(o[n]=e[n]);return o}var s=["onClick","reloadDocument","replace","state","target","to"];function l(e){var t=e.basename,n=e.children,c=e.window,u=Object(o.useRef)();null==u.current&&(u.current=Object(i.b)({window:c}));var s=u.current,l=Object(o.useState)({action:s.action,location:s.location}),f=Object(r.a)(l,2),d=f[0],p=f[1];return Object(o.useLayoutEffect)((function(){return s.listen(p)}),[s]),Object(o.createElement)(a.b,{basename:t,children:n,location:d.location,navigationType:d.action,navigator:s})}var f=Object(o.forwardRef)((function(e,t){var n=e.onClick,r=e.reloadDocument,l=e.replace,f=void 0!==l&&l,d=e.state,p=e.target,h=e.to,v=u(e,s),m=Object(a.d)(h),g=function(e,t){var n=void 0===t?{}:t,r=n.target,c=n.replace,u=n.state,s=Object(a.f)(),l=Object(a.e)(),f=Object(a.h)(e);return Object(o.useCallback)((function(t){if(0===t.button&&(!r||"_self"===r)&&!function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(t)){t.preventDefault();var n=!!c||Object(i.e)(l)===Object(i.e)(f);s(e,{replace:n,state:u})}}),[l,s,f,c,u,r,e])}(h,{replace:f,state:d,target:p});return Object(o.createElement)("a",c({},v,{href:m,onClick:function(e){n&&n(e),e.defaultPrevented||r||g(e)},ref:t,target:p}))}))},function(e,t,n){"use strict";function r(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;r3?t.i-4:t.i:Array.isArray(e)?1:d(e)?2:p(e)?3:0}function u(e,t){return 2===c(e)?e.has(t):Object.prototype.hasOwnProperty.call(e,t)}function s(e,t){return 2===c(e)?e.get(t):e[t]}function l(e,t,n){var r=c(e);2===r?e.set(t,n):3===r?(e.delete(t),e.add(n)):e[t]=n}function f(e,t){return e===t?0!==e||1/e==1/t:e!=e&&t!=t}function d(e){return W&&e instanceof Map}function p(e){return H&&e instanceof Set}function h(e){return e.o||e.t}function v(e){if(Array.isArray(e))return Array.prototype.slice.call(e);var t=G(e);delete t[q];for(var n=K(t),r=0;r1&&(e.set=e.add=e.clear=e.delete=g),Object.freeze(e),t&&a(e,(function(e,t){return m(t,!0)}),!0)),e}function g(){r(2)}function b(e){return null==e||"object"!=typeof e||Object.isFrozen(e)}function y(e){var t=Q[e];return t||r(18,e),t}function w(e,t){Q[e]||(Q[e]=t)}function O(){return F}function j(e,t){t&&(y("Patches"),e.u=[],e.s=[],e.v=t)}function x(e){E(e),e.p.forEach(k),e.p=null}function E(e){e===F&&(F=e.l)}function _(e){return F={p:[],l:F,h:e,m:!0,_:0}}function k(e){var t=e[q];0===t.i||1===t.i?t.j():t.O=!0}function S(e,t){t._=t.p.length;var n=t.p[0],o=void 0!==e&&e!==n;return t.h.g||y("ES5").S(t,e,o),o?(n[q].P&&(x(t),r(4)),i(e)&&(e=C(t,e),t.l||M(t,e)),t.u&&y("Patches").M(n[q],e,t.u,t.s)):e=C(t,n,[]),x(t),t.u&&t.v(t.u,t.s),e!==$?e:void 0}function C(e,t,n){if(b(t))return t;var r=t[q];if(!r)return a(t,(function(o,i){return P(e,r,t,o,i,n)}),!0),t;if(r.A!==e)return t;if(!r.P)return M(e,r.t,!0),r.t;if(!r.I){r.I=!0,r.A._--;var o=4===r.i||5===r.i?r.o=v(r.k):r.o;a(3===r.i?new Set(o):o,(function(t,i){return P(e,r,o,t,i,n)})),M(e,o,!1),n&&e.u&&y("Patches").R(r,n,e.u,e.s)}return r.o}function P(e,t,n,r,a,c){if(o(a)){var s=C(e,a,c&&t&&3!==t.i&&!u(t.D,r)?c.concat(r):void 0);if(l(n,r,s),!o(s))return;e.m=!1}if(i(a)&&!b(a)){if(!e.h.F&&e._<1)return;C(e,a),t&&t.A.l||M(e,a)}}function M(e,t,n){void 0===n&&(n=!1),e.h.F&&e.m&&m(t,n)}function T(e,t){var n=e[q];return(n?h(n):e)[t]}function N(e,t){if(t in e)for(var n=Object.getPrototypeOf(e);n;){var r=Object.getOwnPropertyDescriptor(n,t);if(r)return r;n=Object.getPrototypeOf(n)}}function R(e){e.P||(e.P=!0,e.l&&R(e.l))}function A(e){e.o||(e.o=v(e.t))}function L(e,t,n){var r=d(t)?y("MapSet").N(t,n):p(t)?y("MapSet").T(t,n):e.g?function(e,t){var n=Array.isArray(e),r={i:n?1:0,A:t?t.A:O(),P:!1,I:!1,D:{},l:t,t:e,k:null,o:null,j:null,C:!1},o=r,i=Z;n&&(o=[r],i=J);var a=Proxy.revocable(o,i),c=a.revoke,u=a.proxy;return r.k=u,r.j=c,u}(t,n):y("ES5").J(t,n);return(n?n.A:O()).p.push(r),r}function I(e){return o(e)||r(22,e),function e(t){if(!i(t))return t;var n,r=t[q],o=c(t);if(r){if(!r.P&&(r.i<4||!y("ES5").K(r)))return r.t;r.I=!0,n=D(t,o),r.I=!1}else n=D(t,o);return a(n,(function(t,o){r&&s(r.t,t)===o||l(n,t,e(o))})),3===o?new Set(n):n}(e)}function D(e,t){switch(t){case 2:return new Map(e);case 3:return Array.from(e)}return v(e)}function z(){function e(e,t){var n=i[e];return n?n.enumerable=t:i[e]=n={configurable:!0,enumerable:t,get:function(){var t=this[q];return Z.get(t,e)},set:function(t){var n=this[q];Z.set(n,e,t)}},n}function t(e){for(var t=e.length-1;t>=0;t--){var o=e[t][q];if(!o.P)switch(o.i){case 5:r(o)&&R(o);break;case 4:n(o)&&R(o)}}}function n(e){for(var t=e.t,n=e.k,r=K(n),o=r.length-1;o>=0;o--){var i=r[o];if(i!==q){var a=t[i];if(void 0===a&&!u(t,i))return!0;var c=n[i],s=c&&c[q];if(s?s.t!==a:!f(c,a))return!0}}var l=!!t[q];return r.length!==K(t).length+(l?0:1)}function r(e){var t=e.k;if(t.length!==e.t.length)return!0;var n=Object.getOwnPropertyDescriptor(t,t.length-1);return!(!n||n.get)}var i={};w("ES5",{J:function(t,n){var r=Array.isArray(t),o=function(t,n){if(t){for(var r=Array(n.length),o=0;o1?r-1:0),i=1;i1?r-1:0),i=1;i=0;n--){var r=t[n];if(0===r.path.length&&"replace"===r.op){e=r.value;break}}n>-1&&(t=t.slice(n+1));var i=y("Patches").$;return o(e)?i(e,t):this.produce(e,(function(e){return i(e,t)}))},e}()),te=ee.produce,ne=(ee.produceWithPatches.bind(ee),ee.setAutoFreeze.bind(ee),ee.setUseProxies.bind(ee),ee.applyPatches.bind(ee),ee.createDraft.bind(ee),ee.finishDraft.bind(ee),te);n(145);function re(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function oe(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function ie(e){for(var t=1;t0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]=e.length?{done:!0}:{done:!1,value:e[o++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,c=!0,u=!1;return{s:function(){n=e[Symbol.iterator]()},n:function(){var e=n.next();return c=e.done,e},e:function(e){u=!0,a=e},f:function(){try{c||null==n.return||n.return()}finally{if(u)throw a}}}}},function(e,t,n){"use strict";var r=n(188),o=Object(r.a)();t.a=o},function(e,t,n){"use strict";var r=n(0),o=r.createContext();t.a=o},function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));var r=n(0),o=n(97);function i(){return r.useContext(o.a)}},function(e,t,n){"use strict";function r(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}n.d(t,"a",(function(){return r}))},function(e,t,n){var r=n(347),o=n(352);e.exports=function(e,t){var n=o(e,t);return r(n)?n:void 0}},function(e,t,n){var r=n(89),o=n(348),i=n(349),a=r?r.toStringTag:void 0;e.exports=function(e){return null==e?void 0===e?"[object Undefined]":"[object Null]":a&&a in Object(e)?o(e):i(e)}},function(e,t,n){var r=n(207),o=n(372),i=n(65);e.exports=function(e){return i(e)?r(e,!0):o(e)}},function(e,t){e.exports=function(e){return e}},function(e,t,n){"use strict";e.exports=n(307)},function(e,t,n){"use strict";n.d(t,"a",(function(){return u})),n.d(t,"b",(function(){return s})),n.d(t,"c",(function(){return l}));var r=n(0),o=(n(179),n(36)),i=(n(332),n(111),n(94),n(54)),a=n(68),c=n(146),u=Object(o.e)((function(e,t){var n=e.styles,u=Object(a.a)([n],void 0,Object(r.useContext)(o.b)),s=Object(r.useRef)();return Object(r.useLayoutEffect)((function(){var e=t.key+"-global",n=new c.a({key:e,nonce:t.sheet.nonce,container:t.sheet.container,speedy:t.sheet.isSpeedy}),r=!1,o=document.querySelector('style[data-emotion="'+e+" "+u.name+'"]');return t.sheet.tags.length&&(n.before=t.sheet.tags[0]),null!==o&&(r=!0,o.setAttribute("data-emotion",e),n.hydrate([o])),s.current=[n,r],function(){n.flush()}}),[t]),Object(r.useLayoutEffect)((function(){var e=s.current,n=e[0];if(e[1])e[1]=!1;else{if(void 0!==u.next&&Object(i.b)(t,u.next,!0),n.tags.length){var r=n.tags[n.tags.length-1].nextElementSibling;n.before=r,n.flush()}t.insert("",u,n,!1)}}),[t,u.name]),null}));function s(){for(var e=arguments.length,t=new Array(e),n=0;n0&&void 0!==arguments[0]?arguments[0]:i;return Object(o.a)(e)}},function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));var r=n(181),o={active:"Mui-active",checked:"Mui-checked",completed:"Mui-completed",disabled:"Mui-disabled",error:"Mui-error",expanded:"Mui-expanded",focused:"Mui-focused",focusVisible:"Mui-focusVisible",required:"Mui-required",selected:"Mui-selected"};function i(e,t){return o[t]||"".concat(r.a.generate(e),"-").concat(t)}},function(e,t,n){"use strict";n.d(t,"c",(function(){return u})),n.d(t,"a",(function(){return s})),n.d(t,"b",(function(){return l})),n.d(t,"d",(function(){return f}));var r=n(153);function o(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return Math.min(Math.max(t,e),n)}function i(e){if(e.type)return e;if("#"===e.charAt(0))return i(function(e){e=e.substr(1);var t=new RegExp(".{1,".concat(e.length>=6?2:1,"}"),"g"),n=e.match(t);return n&&1===n[0].length&&(n=n.map((function(e){return e+e}))),n?"rgb".concat(4===n.length?"a":"","(").concat(n.map((function(e,t){return t<3?parseInt(e,16):Math.round(parseInt(e,16)/255*1e3)/1e3})).join(", "),")"):""}(e));var t=e.indexOf("("),n=e.substring(0,t);if(-1===["rgb","rgba","hsl","hsla","color"].indexOf(n))throw new Error(Object(r.a)(9,e));var o,a=e.substring(t+1,e.length-1);if("color"===n){if(o=(a=a.split(" ")).shift(),4===a.length&&"/"===a[3].charAt(0)&&(a[3]=a[3].substr(1)),-1===["srgb","display-p3","a98-rgb","prophoto-rgb","rec-2020"].indexOf(o))throw new Error(Object(r.a)(10,o))}else a=a.split(",");return{type:n,values:a=a.map((function(e){return parseFloat(e)})),colorSpace:o}}function a(e){var t=e.type,n=e.colorSpace,r=e.values;return-1!==t.indexOf("rgb")?r=r.map((function(e,t){return t<3?parseInt(e,10):e})):-1!==t.indexOf("hsl")&&(r[1]="".concat(r[1],"%"),r[2]="".concat(r[2],"%")),r=-1!==t.indexOf("color")?"".concat(n," ").concat(r.join(" ")):"".concat(r.join(", ")),"".concat(t,"(").concat(r,")")}function c(e){var t="hsl"===(e=i(e)).type?i(function(e){var t=(e=i(e)).values,n=t[0],r=t[1]/100,o=t[2]/100,c=r*Math.min(o,1-o),u=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:(e+n/30)%12;return o-c*Math.max(Math.min(t-3,9-t,1),-1)},s="rgb",l=[Math.round(255*u(0)),Math.round(255*u(8)),Math.round(255*u(4))];return"hsla"===e.type&&(s+="a",l.push(t[3])),a({type:s,values:l})}(e)).values:e.values;return t=t.map((function(t){return"color"!==e.type&&(t/=255),t<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4)})),Number((.2126*t[0]+.7152*t[1]+.0722*t[2]).toFixed(3))}function u(e,t){var n=c(e),r=c(t);return(Math.max(n,r)+.05)/(Math.min(n,r)+.05)}function s(e,t){return e=i(e),t=o(t),"rgb"!==e.type&&"hsl"!==e.type||(e.type+="a"),"color"===e.type?e.values[3]="/".concat(t):e.values[3]=t,a(e)}function l(e,t){if(e=i(e),t=o(t),-1!==e.type.indexOf("hsl"))e.values[2]*=1-t;else if(-1!==e.type.indexOf("rgb")||-1!==e.type.indexOf("color"))for(var n=0;n<3;n+=1)e.values[n]*=1-t;return a(e)}function f(e,t){if(e=i(e),t=o(t),-1!==e.type.indexOf("hsl"))e.values[2]+=(100-e.values[2])*t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]+=(255-e.values[n])*t;else if(-1!==e.type.indexOf("color"))for(var r=0;r<3;r+=1)e.values[r]+=(1-e.values[r])*t;return a(e)}},,,function(e,t){e.exports=function(e,t){return e===t||e!==e&&t!==t}},function(e,t,n){var r=n(52).Symbol;e.exports=r},function(e,t,n){(function(e){var r=n(52),o=n(368),i=t&&!t.nodeType&&t,a=i&&"object"==typeof e&&e&&!e.nodeType&&e,c=a&&a.exports===i?r.Buffer:void 0,u=(c?c.isBuffer:void 0)||o;e.exports=u}).call(this,n(124)(e))},function(e,t,n){var r=n(377),o=n(162),i=n(378),a=n(216),c=n(379),u=n(78),s=n(205),l="[object Map]",f="[object Promise]",d="[object Set]",p="[object WeakMap]",h="[object DataView]",v=s(r),m=s(o),g=s(i),b=s(a),y=s(c),w=u;(r&&w(new r(new ArrayBuffer(1)))!=h||o&&w(new o)!=l||i&&w(i.resolve())!=f||a&&w(new a)!=d||c&&w(new c)!=p)&&(w=function(e){var t=u(e),n="[object Object]"==t?e.constructor:void 0,r=n?s(n):"";if(r)switch(r){case v:return h;case m:return l;case g:return f;case b:return d;case y:return p}return t}),e.exports=w},function(e,t,n){var r=n(78),o=n(58);e.exports=function(e){return"symbol"==typeof e||o(e)&&"[object Symbol]"==r(e)}},function(e,t,n){"use strict";n.d(t,"a",(function(){return p}));var r=n(17),o=n(18),i=n(59),a=n(56),c=n(37),u=n(24),s=n(23),l=n(62),f=n(48),d=n(53),p=function(e){Object(u.a)(n,e);var t=Object(s.a)(n);function n(e){var o;return Object(r.a)(this,n),(o=t.call(this)).writable=!1,Object(d.a)(Object(i.a)(o),e),o.opts=e,o.query=e.query,o.readyState="",o.socket=e.socket,o}return Object(o.a)(n,[{key:"onError",value:function(e,t){var r=new Error(e);return r.type="TransportError",r.description=t,Object(a.a)(Object(c.a)(n.prototype),"emit",this).call(this,"error",r),this}},{key:"open",value:function(){return"closed"!==this.readyState&&""!==this.readyState||(this.readyState="opening",this.doOpen()),this}},{key:"close",value:function(){return"opening"!==this.readyState&&"open"!==this.readyState||(this.doClose(),this.onClose()),this}},{key:"send",value:function(e){"open"===this.readyState&&this.write(e)}},{key:"onOpen",value:function(){this.readyState="open",this.writable=!0,Object(a.a)(Object(c.a)(n.prototype),"emit",this).call(this,"open")}},{key:"onData",value:function(e){var t=Object(l.a)(e,this.socket.binaryType);this.onPacket(t)}},{key:"onPacket",value:function(e){Object(a.a)(Object(c.a)(n.prototype),"emit",this).call(this,"packet",e)}},{key:"onClose",value:function(){this.readyState="closed",Object(a.a)(Object(c.a)(n.prototype),"emit",this).call(this,"close")}}]),n}(f.Emitter)},function(e,t,n){"use strict";var r=n(305),o={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},i={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},a={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},c={};function u(e){return r.isMemo(e)?a:c[e.$$typeof]||o}c[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},c[r.Memo]=a;var s=Object.defineProperty,l=Object.getOwnPropertyNames,f=Object.getOwnPropertySymbols,d=Object.getOwnPropertyDescriptor,p=Object.getPrototypeOf,h=Object.prototype;e.exports=function e(t,n,r){if("string"!==typeof n){if(h){var o=p(n);o&&o!==h&&e(t,o,r)}var a=l(n);f&&(a=a.concat(f(n)));for(var c=u(t),v=u(n),m=0;m96?f:d},h=function(e,t,n){var r;if(t){var o=t.shouldForwardProp;r=e.__emotion_forwardProp&&o?function(t){return e.__emotion_forwardProp(t)&&o(t)}:o}return"function"!==typeof r&&n&&(r=e.__emotion_forwardProp),r},v=function(){return null},m=function e(t,n){var o,i,a=t.__emotion_real===t,f=a&&t.__emotion_base||t;void 0!==n&&(o=n.label,i=n.target);var d=h(t,n,a),m=d||p(f),g=!m("as");return function(){var b=arguments,y=a&&void 0!==t.__emotion_styles?t.__emotion_styles.slice(0):[];if(void 0!==o&&y.push("label:"+o+";"),null==b[0]||void 0===b[0].raw)y.push.apply(y,b);else{0,y.push(b[0][0]);for(var w=b.length,O=1;O=0||(o[n]=e[n]);return o}var g={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},b={rel:["amphtml","canonical","alternate"]},y={type:["application/ld+json"]},w={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},O=Object.keys(g).map((function(e){return g[e]})),j={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},x=Object.keys(j).reduce((function(e,t){return e[j[t]]=t,e}),{}),E=function(e,t){for(var n=e.length-1;n>=0;n-=1){var r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},_=function(e){var t=E(e,g.TITLE),n=E(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,(function(){return t}));var r=E(e,"defaultTitle");return t||r||void 0},k=function(e){return E(e,"onChangeClientState")||function(){}},S=function(e,t){return t.filter((function(t){return void 0!==t[e]})).map((function(t){return t[e]})).reduce((function(e,t){return p({},e,t)}),{})},C=function(e,t){return t.filter((function(e){return void 0!==e[g.BASE]})).map((function(e){return e[g.BASE]})).reverse().reduce((function(t,n){if(!t.length)for(var r=Object.keys(n),o=0;o/g,">").replace(/"/g,""").replace(/'/g,"'")},L=function(e){return Object.keys(e).reduce((function(t,n){var r=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r}),"")},I=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce((function(t,n){return t[j[n]||n]=e[n],t}),t)},D=function(e,t){return t.map((function(t,n){var r,i=((r={key:n})["data-rh"]=!0,r);return Object.keys(t).forEach((function(e){var n=j[e]||e;"innerHTML"===n||"cssText"===n?i.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:i[n]=t[e]})),o.a.createElement(e,i)}))},z=function(e,t,n){switch(e){case g.TITLE:return{toComponent:function(){return n=t.titleAttributes,(r={key:e=t.title})["data-rh"]=!0,i=I(n,r),[o.a.createElement(g.TITLE,i,e)];var e,n,r,i},toString:function(){return function(e,t,n,r){var o=L(n),i=T(t);return o?"<"+e+' data-rh="true" '+o+">"+A(i,r)+"":"<"+e+' data-rh="true">'+A(i,r)+""}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return I(t)},toString:function(){return L(t)}};default:return{toComponent:function(){return D(e,t)},toString:function(){return function(e,t,n){return t.reduce((function(t,r){var o=Object.keys(r).filter((function(e){return!("innerHTML"===e||"cssText"===e)})).reduce((function(e,t){var o=void 0===r[t]?t:t+'="'+A(r[t],n)+'"';return e?e+" "+o:o}),""),i=r.innerHTML||r.cssText||"",a=-1===R.indexOf(e);return t+"<"+e+' data-rh="true" '+o+(a?"/>":">"+i+"")}),"")}(e,t,n)}}}},B=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,o=e.htmlAttributes,i=e.noscriptTags,a=e.styleTags,c=e.title,u=void 0===c?"":c,s=e.titleAttributes,l=e.linkTags,f=e.metaTags,d=e.scriptTags,p={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var h=function(e){var t=e.linkTags,n=e.scriptTags,r=e.encode,o=N(e.metaTags,w),i=N(t,b),a=N(n,y);return{priorityMethods:{toComponent:function(){return[].concat(D(g.META,o.priority),D(g.LINK,i.priority),D(g.SCRIPT,a.priority))},toString:function(){return z(g.META,o.priority,r)+" "+z(g.LINK,i.priority,r)+" "+z(g.SCRIPT,a.priority,r)}},metaTags:o.default,linkTags:i.default,scriptTags:a.default}}(e);p=h.priorityMethods,l=h.linkTags,f=h.metaTags,d=h.scriptTags}return{priority:p,base:z(g.BASE,t,r),bodyAttributes:z("bodyAttributes",n,r),htmlAttributes:z("htmlAttributes",o,r),link:z(g.LINK,l,r),meta:z(g.META,f,r),noscript:z(g.NOSCRIPT,i,r),script:z(g.SCRIPT,d,r),style:z(g.STYLE,a,r),title:z(g.TITLE,{title:u,titleAttributes:s},r)}},F=function e(t,n){var r=this;this.instances=[],this.value={setHelmet:function(e){r.context.helmet=e},helmetInstances:{get:function(){return r.instances},add:function(e){r.instances.push(e)},remove:function(e){var t=r.instances.indexOf(e);r.instances.splice(t,1)}}},this.context=t,n&&(this.instances=n),e.canUseDOM||(t.helmet=B({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},U=o.a.createContext({}),W=a.a.shape({setHelmet:a.a.func,helmetInstances:a.a.shape({get:a.a.func,add:a.a.func,remove:a.a.func})}),H="undefined"!=typeof document,V=function(e){function t(t){var n;return(n=e.call(this,t)||this).helmetData=new F(n.props.context),n}return h(t,e),t.prototype.render=function(){return o.a.createElement(U.Provider,{value:this.helmetData.value},this.props.children)},t}(r.Component);V.canUseDOM=H,V.propTypes={context:a.a.shape({helmet:a.a.shape()}),children:a.a.node.isRequired},V.defaultProps={context:{}},V.displayName="HelmetProvider";var $=function(e,t){var n,r=document.head||document.querySelector(g.HEAD),o=r.querySelectorAll(e+"[data-rh]"),i=[].slice.call(o),a=[];return t&&t.length&&t.forEach((function(t){var r=document.createElement(e);for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&("innerHTML"===o?r.innerHTML=t.innerHTML:"cssText"===o?r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText)):r.setAttribute(o,void 0===t[o]?"":t[o]));r.setAttribute("data-rh","true"),i.some((function(e,t){return n=t,r.isEqualNode(e)}))?i.splice(n,1):a.push(r)})),i.forEach((function(e){return e.parentNode.removeChild(e)})),a.forEach((function(e){return r.appendChild(e)})),{oldTags:i,newTags:a}},Y=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute("data-rh"),o=r?r.split(","):[],i=[].concat(o),a=Object.keys(t),c=0;c=0;f-=1)n.removeAttribute(i[f]);o.length===i.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==a.join(",")&&n.setAttribute("data-rh",a.join(","))}},q=function(e,t){var n=e.baseTag,r=e.htmlAttributes,o=e.linkTags,i=e.metaTags,a=e.noscriptTags,c=e.onChangeClientState,u=e.scriptTags,s=e.styleTags,l=e.title,f=e.titleAttributes;Y(g.BODY,e.bodyAttributes),Y(g.HTML,r),function(e,t){void 0!==e&&document.title!==e&&(document.title=T(e)),Y(g.TITLE,t)}(l,f);var d={baseTag:$(g.BASE,n),linkTags:$(g.LINK,o),metaTags:$(g.META,i),noscriptTags:$(g.NOSCRIPT,a),scriptTags:$(g.SCRIPT,u),styleTags:$(g.STYLE,s)},p={},h={};Object.keys(d).forEach((function(e){var t=d[e],n=t.newTags,r=t.oldTags;n.length&&(p[e]=n),r.length&&(h[e]=d[e].oldTags)})),t&&t(),c(e,p,h)},X=null,K=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),o=0;o elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren;return p({},r,((t={})[n.type]=[].concat(r[n.type]||[],[p({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,r=e.child,o=e.newProps,i=e.newChildProps,a=e.nestedChildren;switch(r.type){case g.TITLE:return p({},o,((t={})[r.type]=a,t.titleAttributes=p({},i),t));case g.BODY:return p({},o,{bodyAttributes:p({},i)});case g.HTML:return p({},o,{htmlAttributes:p({},i)});default:return p({},o,((n={})[r.type]=p({},i),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=p({},t);return Object.keys(e).forEach((function(t){var r;n=p({},n,((r={})[t]=e[t],r))})),n},n.warnOnInvalidChildren=function(e,t){return l()(O.some((function(t){return e.type===t})),"function"==typeof e.type?"You may be attempting to nest components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+O.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),l()(!t||"string"==typeof t||Array.isArray(t)&&!t.some((function(e){return"string"!=typeof e})),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``} ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,r={};return o.a.Children.forEach(e,(function(e){if(e&&e.props){var o=e.props,i=o.children,a=m(o,G),c=Object.keys(a).reduce((function(e,t){return e[x[t]||t]=a[t],e}),{}),u=e.type;switch("symbol"==typeof u?u=u.toString():n.warnOnInvalidChildren(e,i),u){case g.FRAGMENT:t=n.mapChildrenToProps(i,t);break;case g.LINK:case g.META:case g.NOSCRIPT:case g.SCRIPT:case g.STYLE:r=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:r,newChildProps:c,nestedChildren:i});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:c,nestedChildren:i})}}})),this.mapArrayTypeChildrenToProps(r,t)},n.render=function(){var e=this.props,t=e.children,n=m(e,Q),r=p({},n),i=n.helmetData;return t&&(r=this.mapChildrenToProps(t,r)),!i||i instanceof F||(i=new F(i.context,i.instances)),i?o.a.createElement(K,p({},r,{context:i.value})):o.a.createElement(U.Consumer,null,(function(e){return o.a.createElement(K,p({},r,{context:e}))}))},t}(r.Component);Z.propTypes={base:a.a.object,bodyAttributes:a.a.object,children:a.a.oneOfType([a.a.arrayOf(a.a.node),a.a.node]),defaultTitle:a.a.string,defer:a.a.bool,encodeSpecialCharacters:a.a.bool,htmlAttributes:a.a.object,link:a.a.arrayOf(a.a.object),meta:a.a.arrayOf(a.a.object),noscript:a.a.arrayOf(a.a.object),onChangeClientState:a.a.func,script:a.a.arrayOf(a.a.object),style:a.a.arrayOf(a.a.object),title:a.a.string,titleAttributes:a.a.object,titleTemplate:a.a.string,prioritizeSeoTags:a.a.bool,helmetData:a.a.object},Z.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},Z.displayName="Helmet"},function(e,t,n){"use strict";function r(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*"}}};r.forEach(["delete","get","head"],(function(e){u.headers[e]={}})),r.forEach(["post","put","patch"],(function(e){u.headers[e]=r.merge(a)})),e.exports=u}).call(this,n(316))},function(e,t,n){"use strict";function r(e){this.message=e}r.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},r.prototype.__CANCEL__=!0,e.exports=r},function(e,t,n){var r=n(128),o=n(342),i=n(343),a=n(344),c=n(345),u=n(346);function s(e){var t=this.__data__=new r(e);this.size=t.size}s.prototype.clear=o,s.prototype.delete=i,s.prototype.get=a,s.prototype.has=c,s.prototype.set=u,e.exports=s},function(e,t,n){var r=n(337),o=n(338),i=n(339),a=n(340),c=n(341);function u(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e-1){var i=n[o];return o>0&&(n.splice(o,1),n.unshift(i)),i.value}return r}return{get:o,put:function(t,i){o(t)===r&&(n.unshift({key:t,value:i}),n.length>e&&n.pop())},getEntries:function(){return n},clear:function(){n=[]}}}(u,l);function d(){var t=f.get(arguments);if(t===r){if(t=e.apply(null,arguments),s){var n=f.getEntries(),o=n.find((function(e){return s(e.value,t)}));o&&(t=o.value)}f.put(arguments,t)}return t}return d.clearCache=function(){return f.clear()},d}function a(e){var t=Array.isArray(e[0])?e[0]:e;if(!t.every((function(e){return"function"===typeof e}))){var n=t.map((function(e){return"function"===typeof e?"function "+(e.name||"unnamed")+"()":typeof e})).join(", ");throw new Error("createSelector expects all input-selectors to be functions, but received the following types: ["+n+"]")}return t}function c(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r1&&void 0!==arguments[1]&&arguments[1];return e&&(r(e.value)&&""!==e.value||t&&r(e.defaultValue)&&""!==e.defaultValue)}n.d(t,"a",(function(){return o}))},function(e,t,n){"use strict";var r,o="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(""),i={},a=0,c=0;function u(e){var t="";do{t=o[e%64]+t,e=Math.floor(e/64)}while(e>0);return t}function s(){var e=u(+new Date);return e!==r?(a=0,r=e):e+"."+u(a++)}for(;c<64;c++)i[o[c]]=c;s.encode=u,s.decode=function(e){var t=0;for(c=0;ca){var c=i;i=a,a=c}return i+"\x01"+a+"\x01"+(r.isUndefined(o)?"\0":o)}function s(e,t,n,r){var o=""+t,i=""+n;if(!e&&o>i){var a=o;o=i,i=a}var c={v:o,w:i};return r&&(c.name=r),c}function l(e,t){return u(e,t.v,t.w,t.name)}i.prototype._nodeCount=0,i.prototype._edgeCount=0,i.prototype.isDirected=function(){return this._isDirected},i.prototype.isMultigraph=function(){return this._isMultigraph},i.prototype.isCompound=function(){return this._isCompound},i.prototype.setGraph=function(e){return this._label=e,this},i.prototype.graph=function(){return this._label},i.prototype.setDefaultNodeLabel=function(e){return r.isFunction(e)||(e=r.constant(e)),this._defaultNodeLabelFn=e,this},i.prototype.nodeCount=function(){return this._nodeCount},i.prototype.nodes=function(){return r.keys(this._nodes)},i.prototype.sources=function(){var e=this;return r.filter(this.nodes(),(function(t){return r.isEmpty(e._in[t])}))},i.prototype.sinks=function(){var e=this;return r.filter(this.nodes(),(function(t){return r.isEmpty(e._out[t])}))},i.prototype.setNodes=function(e,t){var n=arguments,o=this;return r.each(e,(function(e){n.length>1?o.setNode(e,t):o.setNode(e)})),this},i.prototype.setNode=function(e,t){return r.has(this._nodes,e)?(arguments.length>1&&(this._nodes[e]=t),this):(this._nodes[e]=arguments.length>1?t:this._defaultNodeLabelFn(e),this._isCompound&&(this._parent[e]=o,this._children[e]={},this._children["\0"][e]=!0),this._in[e]={},this._preds[e]={},this._out[e]={},this._sucs[e]={},++this._nodeCount,this)},i.prototype.node=function(e){return this._nodes[e]},i.prototype.hasNode=function(e){return r.has(this._nodes,e)},i.prototype.removeNode=function(e){var t=this;if(r.has(this._nodes,e)){var n=function(e){t.removeEdge(t._edgeObjs[e])};delete this._nodes[e],this._isCompound&&(this._removeFromParentsChildList(e),delete this._parent[e],r.each(this.children(e),(function(e){t.setParent(e)})),delete this._children[e]),r.each(r.keys(this._in[e]),n),delete this._in[e],delete this._preds[e],r.each(r.keys(this._out[e]),n),delete this._out[e],delete this._sucs[e],--this._nodeCount}return this},i.prototype.setParent=function(e,t){if(!this._isCompound)throw new Error("Cannot set parent in a non-compound graph");if(r.isUndefined(t))t=o;else{for(var n=t+="";!r.isUndefined(n);n=this.parent(n))if(n===e)throw new Error("Setting "+t+" as parent of "+e+" would create a cycle");this.setNode(t)}return this.setNode(e),this._removeFromParentsChildList(e),this._parent[e]=t,this._children[t][e]=!0,this},i.prototype._removeFromParentsChildList=function(e){delete this._children[this._parent[e]][e]},i.prototype.parent=function(e){if(this._isCompound){var t=this._parent[e];if(t!==o)return t}},i.prototype.children=function(e){if(r.isUndefined(e)&&(e=o),this._isCompound){var t=this._children[e];if(t)return r.keys(t)}else{if(e===o)return this.nodes();if(this.hasNode(e))return[]}},i.prototype.predecessors=function(e){var t=this._preds[e];if(t)return r.keys(t)},i.prototype.successors=function(e){var t=this._sucs[e];if(t)return r.keys(t)},i.prototype.neighbors=function(e){var t=this.predecessors(e);if(t)return r.union(t,this.successors(e))},i.prototype.isLeaf=function(e){return 0===(this.isDirected()?this.successors(e):this.neighbors(e)).length},i.prototype.filterNodes=function(e){var t=new this.constructor({directed:this._isDirected,multigraph:this._isMultigraph,compound:this._isCompound});t.setGraph(this.graph());var n=this;r.each(this._nodes,(function(n,r){e(r)&&t.setNode(r,n)})),r.each(this._edgeObjs,(function(e){t.hasNode(e.v)&&t.hasNode(e.w)&&t.setEdge(e,n.edge(e))}));var o={};function i(e){var r=n.parent(e);return void 0===r||t.hasNode(r)?(o[e]=r,r):r in o?o[r]:i(r)}return this._isCompound&&r.each(t.nodes(),(function(e){t.setParent(e,i(e))})),t},i.prototype.setDefaultEdgeLabel=function(e){return r.isFunction(e)||(e=r.constant(e)),this._defaultEdgeLabelFn=e,this},i.prototype.edgeCount=function(){return this._edgeCount},i.prototype.edges=function(){return r.values(this._edgeObjs)},i.prototype.setPath=function(e,t){var n=this,o=arguments;return r.reduce(e,(function(e,r){return o.length>1?n.setEdge(e,r,t):n.setEdge(e,r),r})),this},i.prototype.setEdge=function(){var e,t,n,o,i=!1,c=arguments[0];"object"===typeof c&&null!==c&&"v"in c?(e=c.v,t=c.w,n=c.name,2===arguments.length&&(o=arguments[1],i=!0)):(e=c,t=arguments[1],n=arguments[3],arguments.length>2&&(o=arguments[2],i=!0)),e=""+e,t=""+t,r.isUndefined(n)||(n=""+n);var l=u(this._isDirected,e,t,n);if(r.has(this._edgeLabels,l))return i&&(this._edgeLabels[l]=o),this;if(!r.isUndefined(n)&&!this._isMultigraph)throw new Error("Cannot set a named edge when isMultigraph = false");this.setNode(e),this.setNode(t),this._edgeLabels[l]=i?o:this._defaultEdgeLabelFn(e,t,n);var f=s(this._isDirected,e,t,n);return e=f.v,t=f.w,Object.freeze(f),this._edgeObjs[l]=f,a(this._preds[t],e),a(this._sucs[e],t),this._in[t][l]=f,this._out[e][l]=f,this._edgeCount++,this},i.prototype.edge=function(e,t,n){var r=1===arguments.length?l(this._isDirected,arguments[0]):u(this._isDirected,e,t,n);return this._edgeLabels[r]},i.prototype.hasEdge=function(e,t,n){var o=1===arguments.length?l(this._isDirected,arguments[0]):u(this._isDirected,e,t,n);return r.has(this._edgeLabels,o)},i.prototype.removeEdge=function(e,t,n){var r=1===arguments.length?l(this._isDirected,arguments[0]):u(this._isDirected,e,t,n),o=this._edgeObjs[r];return o&&(e=o.v,t=o.w,delete this._edgeLabels[r],delete this._edgeObjs[r],c(this._preds[t],e),c(this._sucs[e],t),delete this._in[t][r],delete this._out[e][r],this._edgeCount--),this},i.prototype.inEdges=function(e,t){var n=this._in[e];if(n){var o=r.values(n);return t?r.filter(o,(function(e){return e.v===t})):o}},i.prototype.outEdges=function(e,t){var n=this._out[e];if(n){var o=r.values(n);return t?r.filter(o,(function(e){return e.w===t})):o}},i.prototype.nodeEdges=function(e,t){var n=this.inEdges(e,t);if(n)return n.concat(this.outEdges(e,t))}},function(e,t,n){var r=n(77)(n(52),"Map");e.exports=r},function(e,t,n){var r=n(353),o=n(360),i=n(362),a=n(363),c=n(364);function u(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e<=9007199254740991}},function(e,t,n){(function(e){var r=n(204),o=t&&!t.nodeType&&t,i=o&&"object"==typeof e&&e&&!e.nodeType&&e,a=i&&i.exports===o&&r.process,c=function(){try{var e=i&&i.require&&i.require("util").types;return e||a&&a.binding&&a.binding("util")}catch(t){}}();e.exports=c}).call(this,n(124)(e))},function(e,t,n){var r=n(136),o=n(370),i=Object.prototype.hasOwnProperty;e.exports=function(e){if(!r(e))return o(e);var t=[];for(var n in Object(e))i.call(e,n)&&"constructor"!=n&&t.push(n);return t}},function(e,t,n){var r=n(211),o=n(212),i=Object.prototype.propertyIsEnumerable,a=Object.getOwnPropertySymbols,c=a?function(e){return null==e?[]:(e=Object(e),r(a(e),(function(t){return i.call(e,t)})))}:o;e.exports=c},function(e,t){e.exports=function(e,t){for(var n=-1,r=t.length,o=e.length;++n0&&i(l)?n>1?e(l,n-1,i,a,c):r(c,l):a||(c[c.length]=l)}return c}},function(e,t,n){var r=n(92);e.exports=function(e,t,n){for(var o=-1,i=e.length;++o0?v(k,--E):0,j--,10===_&&(j=1,O--),_}function M(){return _=E2||A(_)>3?"":" "}function B(e,t){for(;--t&&M()&&!(_<48||_>102||_>57&&_<65||_>70&&_<97););return R(e,N()+(t<6&&32==T()&&32==M()))}function F(e){for(;M();)switch(_){case e:return E;case 34:case 39:return F(34===e||39===e?e:_);case 40:41===e&&F(e);break;case 92:M()}return E}function U(e,t){for(;M()&&e+_!==57&&(e+_!==84||47!==T()););return"/*"+R(t,E-1)+"*"+f(47===e?e:M())}function W(e){for(;!A(T());)M();return R(e,E)}function H(e){return I(V("",null,null,null,[""],e=L(e),0,[0],e))}function V(e,t,n,r,o,i,a,c,u){for(var s=0,l=0,d=a,h=0,v=0,m=0,b=1,w=1,O=1,j=0,x="",E=o,_=i,k=r,S=x;w;)switch(m=j,j=M()){case 34:case 39:case 91:case 40:S+=D(j);break;case 9:case 10:case 13:case 32:S+=z(m);break;case 92:S+=B(N()-1,7);continue;case 47:switch(T()){case 42:case 47:y(Y(U(M(),N()),t,n),u);break;default:S+="/"}break;case 123*b:c[s++]=g(S)*O;case 125*b:case 59:case 0:switch(j){case 0:case 125:w=0;case 59+l:v>0&&g(S)-d&&y(v>32?q(S+";",r,n,d-1):q(p(S," ","")+";",r,n,d-2),u);break;case 59:S+=";";default:if(y(k=$(S,t,n,s,l,o,c,x,E=[],_=[],d),i),123===j)if(0===l)V(S,t,k,k,E,i,d,c,_);else switch(h){case 100:case 109:case 115:V(e,k,k,r&&y($(e,k,k,0,0,o,c,x,o,E=[],d),_),o,_,d,c,r?E:_);break;default:V(S,k,k,k,[""],_,d,c,_)}}s=l=v=0,b=O=1,x=S="",d=a;break;case 58:d=1+g(S),v=m;default:if(b<1)if(123==j)--b;else if(125==j&&0==b++&&125==P())continue;switch(S+=f(j),j*b){case 38:O=l>0?1:(S+="\f",-1);break;case 44:c[s++]=(g(S)-1)*O,O=1;break;case 64:45===T()&&(S+=D(M())),h=T(),l=g(x=S+=W(N())),j++;break;case 45:45===m&&2==g(S)&&(b=0)}}return i}function $(e,t,n,r,o,i,a,c,s,f,h){for(var v=o-1,g=0===o?i:[""],y=b(g),w=0,O=0,j=0;w0?g[x]+" "+E:p(E,/&\f/g,g[x])))&&(s[j++]=_);return S(e,t,n,0===o?u:c,s,f,h)}function Y(e,t,n){return S(e,t,n,c,f(_),m(e,2,-2),0)}function q(e,t,n,r){return S(e,t,n,s,m(e,0,r),m(e,r+1,-1),r)}function X(e,t){switch(function(e,t){return(((t<<2^v(e,0))<<2^v(e,1))<<2^v(e,2))<<2^v(e,3)}(e,t)){case 5103:return a+"print-"+e+e;case 5737:case 4201:case 3177:case 3433:case 1641:case 4457:case 2921:case 5572:case 6356:case 5844:case 3191:case 6645:case 3005:case 6391:case 5879:case 5623:case 6135:case 4599:case 4855:case 4215:case 6389:case 5109:case 5365:case 5621:case 3829:return a+e+e;case 5349:case 4246:case 4810:case 6968:case 2756:return a+e+i+e+o+e+e;case 6828:case 4268:return a+e+o+e+e;case 6165:return a+e+o+"flex-"+e+e;case 5187:return a+e+p(e,/(\w+).+(:[^]+)/,a+"box-$1$2"+o+"flex-$1$2")+e;case 5443:return a+e+o+"flex-item-"+p(e,/flex-|-self/,"")+e;case 4675:return a+e+o+"flex-line-pack"+p(e,/align-content|flex-|-self/,"")+e;case 5548:return a+e+o+p(e,"shrink","negative")+e;case 5292:return a+e+o+p(e,"basis","preferred-size")+e;case 6060:return a+"box-"+p(e,"-grow","")+a+e+o+p(e,"grow","positive")+e;case 4554:return a+p(e,/([^-])(transform)/g,"$1"+a+"$2")+e;case 6187:return p(p(p(e,/(zoom-|grab)/,a+"$1"),/(image-set)/,a+"$1"),e,"")+e;case 5495:case 3959:return p(e,/(image-set\([^]*)/,a+"$1$`$1");case 4968:return p(p(e,/(.+:)(flex-)?(.*)/,a+"box-pack:$3"+o+"flex-pack:$3"),/s.+-b[^;]+/,"justify")+a+e+e;case 4095:case 3583:case 4068:case 2532:return p(e,/(.+)-inline(.+)/,a+"$1$2")+e;case 8116:case 7059:case 5753:case 5535:case 5445:case 5701:case 4933:case 4677:case 5533:case 5789:case 5021:case 4765:if(g(e)-1-t>6)switch(v(e,t+1)){case 109:if(45!==v(e,t+4))break;case 102:return p(e,/(.+:)(.+)-([^]+)/,"$1"+a+"$2-$3$1"+i+(108==v(e,t+3)?"$3":"$2-$3"))+e;case 115:return~h(e,"stretch")?X(p(e,"stretch","fill-available"),t)+e:e}break;case 4949:if(115!==v(e,t+1))break;case 6444:switch(v(e,g(e)-3-(~h(e,"!important")&&10))){case 107:return p(e,":",":"+a)+e;case 101:return p(e,/(.+:)([^;!]+)(;|!.+)?/,"$1"+a+(45===v(e,14)?"inline-":"")+"box$3$1"+a+"$2$3$1"+o+"$2box$3")+e}break;case 5936:switch(v(e,t+11)){case 114:return a+e+o+p(e,/[svh]\w+-[tblr]{2}/,"tb")+e;case 108:return a+e+o+p(e,/[svh]\w+-[tblr]{2}/,"tb-rl")+e;case 45:return a+e+o+p(e,/[svh]\w+-[tblr]{2}/,"lr")+e}return a+e+o+e+e}return e}function K(e,t){for(var n="",r=b(e),o=0;o0&&void 0!==arguments[0]?arguments[0]:{},t=e.defaultTheme,n=e.defaultClassName,p=void 0===n?"MuiBox-root":n,h=e.generateClassName,v=Object(c.a)("div")(u.a),m=i.forwardRef((function(e,n){var i=Object(l.a)(t),c=Object(s.a)(e),u=c.className,m=c.component,g=void 0===m?"div":m,b=Object(o.a)(c,d);return Object(f.jsx)(v,Object(r.a)({as:g,ref:n,className:Object(a.a)(u,h?h(p):p),theme:i},b))}));return m}},function(e,t,n){"use strict";n.d(t,"b",(function(){return i}));var r=n(84),o=n(104);function i(e){return Object(r.a)("MuiTableCell",e)}var a=Object(o.a)("MuiTableCell",["root","head","body","footer","sizeSmall","sizeMedium","paddingCheckbox","paddingNone","alignLeft","alignCenter","alignRight","alignJustify","stickyHeader"]);t.a=a},function(e,t,n){e.exports=n(333)},function(e,t,n){e.exports={graphlib:n(51),layout:n(447),debug:n(508),util:{time:n(40).time,notime:n(40).notime},version:n(509)}},function(e,t,n){"use strict";var r=n(510),o=n(529);t.highlight=a,t.highlightAuto=function(e,t){var n,c,u,s,l=t||{},f=l.subset||r.listLanguages(),d=l.prefix,p=f.length,h=-1;null!==d&&void 0!==d||(d=i);if("string"!==typeof e)throw o("Expected `string` for value, got `%s`",e);c={relevance:0,language:null,value:[]},n={relevance:0,language:null,value:[]};for(;++hc.relevance&&(c=u),u.relevance>n.relevance&&(c=n,n=u));c.language&&(n.secondBest=c);return n},t.registerLanguage=function(e,t){r.registerLanguage(e,t)},t.listLanguages=function(){return r.listLanguages()},t.registerAlias=function(e,t){var n,o=e;t&&((o={})[e]=t);for(n in o)r.registerAliases(o[n],{languageName:n})},c.prototype.addText=function(e){var t,n,r=this.stack;if(""===e)return;t=r[r.length-1],(n=t.children[t.children.length-1])&&"text"===n.type?n.value+=e:t.children.push({type:"text",value:e})},c.prototype.addKeyword=function(e,t){this.openNode(t),this.addText(e),this.closeNode()},c.prototype.addSublanguage=function(e,t){var n=this.stack,r=n[n.length-1],o=e.rootNode.children,i=t?{type:"element",tagName:"span",properties:{className:[t]},children:o}:o;r.children=r.children.concat(i)},c.prototype.openNode=function(e){var t=this.stack,n=this.options.classPrefix+e,r=t[t.length-1],o={type:"element",tagName:"span",properties:{className:[n]},children:[]};r.children.push(o),t.push(o)},c.prototype.closeNode=function(){this.stack.pop()},c.prototype.closeAllNodes=u,c.prototype.finalize=u,c.prototype.toHTML=function(){return""};var i="hljs-";function a(e,t,n){var a,u=r.configure({}),s=(n||{}).prefix;if("string"!==typeof e)throw o("Expected `string` for name, got `%s`",e);if(!r.getLanguage(e))throw o("Unknown language: `%s` is not registered",e);if("string"!==typeof t)throw o("Expected `string` for value, got `%s`",t);if(null!==s&&void 0!==s||(s=i),r.configure({__emitter:c,classPrefix:s}),a=r.highlight(t,{language:e,ignoreIllegals:!0}),r.configure(u||{}),a.errorRaised)throw a.errorRaised;return{relevance:a.relevance,language:a.language,value:a.emitter.rootNode.children}}function c(e){this.options=e,this.rootNode={children:[]},this.stack=[this.rootNode]}function u(){}},function(e,t,n){"use strict";var r=n(3),o=n(2),i=n(4),a=n(189),c=n(554);function u(e,t,n){var i;return Object(o.a)({toolbar:(i={minHeight:56},Object(r.a)(i,"".concat(e.up("xs")," and (orientation: landscape)"),{minHeight:48}),Object(r.a)(i,e.up("sm"),{minHeight:64}),i)},n)}var s=n(153),l=n(85),f={black:"#000",white:"#fff"},d={50:"#fafafa",100:"#f5f5f5",200:"#eeeeee",300:"#e0e0e0",400:"#bdbdbd",500:"#9e9e9e",600:"#757575",700:"#616161",800:"#424242",900:"#212121",A100:"#f5f5f5",A200:"#eeeeee",A400:"#bdbdbd",A700:"#616161"},p={50:"#f3e5f5",100:"#e1bee7",200:"#ce93d8",300:"#ba68c8",400:"#ab47bc",500:"#9c27b0",600:"#8e24aa",700:"#7b1fa2",800:"#6a1b9a",900:"#4a148c",A100:"#ea80fc",A200:"#e040fb",A400:"#d500f9",A700:"#aa00ff"},h={50:"#ffebee",100:"#ffcdd2",200:"#ef9a9a",300:"#e57373",400:"#ef5350",500:"#f44336",600:"#e53935",700:"#d32f2f",800:"#c62828",900:"#b71c1c",A100:"#ff8a80",A200:"#ff5252",A400:"#ff1744",A700:"#d50000"},v={50:"#fff3e0",100:"#ffe0b2",200:"#ffcc80",300:"#ffb74d",400:"#ffa726",500:"#ff9800",600:"#fb8c00",700:"#f57c00",800:"#ef6c00",900:"#e65100",A100:"#ffd180",A200:"#ffab40",A400:"#ff9100",A700:"#ff6d00"},m={50:"#e3f2fd",100:"#bbdefb",200:"#90caf9",300:"#64b5f6",400:"#42a5f5",500:"#2196f3",600:"#1e88e5",700:"#1976d2",800:"#1565c0",900:"#0d47a1",A100:"#82b1ff",A200:"#448aff",A400:"#2979ff",A700:"#2962ff"},g={50:"#e1f5fe",100:"#b3e5fc",200:"#81d4fa",300:"#4fc3f7",400:"#29b6f6",500:"#03a9f4",600:"#039be5",700:"#0288d1",800:"#0277bd",900:"#01579b",A100:"#80d8ff",A200:"#40c4ff",A400:"#00b0ff",A700:"#0091ea"},b={50:"#e8f5e9",100:"#c8e6c9",200:"#a5d6a7",300:"#81c784",400:"#66bb6a",500:"#4caf50",600:"#43a047",700:"#388e3c",800:"#2e7d32",900:"#1b5e20",A100:"#b9f6ca",A200:"#69f0ae",A400:"#00e676",A700:"#00c853"},y=["mode","contrastThreshold","tonalOffset"],w={text:{primary:"rgba(0, 0, 0, 0.87)",secondary:"rgba(0, 0, 0, 0.6)",disabled:"rgba(0, 0, 0, 0.38)"},divider:"rgba(0, 0, 0, 0.12)",background:{paper:f.white,default:f.white},action:{active:"rgba(0, 0, 0, 0.54)",hover:"rgba(0, 0, 0, 0.04)",hoverOpacity:.04,selected:"rgba(0, 0, 0, 0.08)",selectedOpacity:.08,disabled:"rgba(0, 0, 0, 0.26)",disabledBackground:"rgba(0, 0, 0, 0.12)",disabledOpacity:.38,focus:"rgba(0, 0, 0, 0.12)",focusOpacity:.12,activatedOpacity:.12}},O={text:{primary:f.white,secondary:"rgba(255, 255, 255, 0.7)",disabled:"rgba(255, 255, 255, 0.5)",icon:"rgba(255, 255, 255, 0.5)"},divider:"rgba(255, 255, 255, 0.12)",background:{paper:"#121212",default:"#121212"},action:{active:f.white,hover:"rgba(255, 255, 255, 0.08)",hoverOpacity:.08,selected:"rgba(255, 255, 255, 0.16)",selectedOpacity:.16,disabled:"rgba(255, 255, 255, 0.3)",disabledBackground:"rgba(255, 255, 255, 0.12)",disabledOpacity:.38,focus:"rgba(255, 255, 255, 0.12)",focusOpacity:.12,activatedOpacity:.24}};function j(e,t,n,r){var o=r.light||r,i=r.dark||1.5*r;e[t]||(e.hasOwnProperty(n)?e[t]=e[n]:"light"===t?e.light=Object(l.d)(e.main,o):"dark"===t&&(e.dark=Object(l.b)(e.main,i)))}function x(e){var t=e.mode,n=void 0===t?"light":t,r=e.contrastThreshold,c=void 0===r?3:r,u=e.tonalOffset,x=void 0===u?.2:u,E=Object(i.a)(e,y),_=e.primary||function(){return"dark"===(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"light")?{main:m[200],light:m[50],dark:m[400]}:{main:m[700],light:m[400],dark:m[800]}}(n),k=e.secondary||function(){return"dark"===(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"light")?{main:p[200],light:p[50],dark:p[400]}:{main:p[500],light:p[300],dark:p[700]}}(n),S=e.error||function(){return"dark"===(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"light")?{main:h[500],light:h[300],dark:h[700]}:{main:h[700],light:h[400],dark:h[800]}}(n),C=e.info||function(){return"dark"===(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"light")?{main:g[400],light:g[300],dark:g[700]}:{main:g[700],light:g[500],dark:g[900]}}(n),P=e.success||function(){return"dark"===(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"light")?{main:b[400],light:b[300],dark:b[700]}:{main:b[800],light:b[500],dark:b[900]}}(n),M=e.warning||function(){return"dark"===(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"light")?{main:v[400],light:v[300],dark:v[700]}:{main:"#ed6c02",light:v[500],dark:v[900]}}(n);function T(e){return Object(l.c)(e,O.text.primary)>=c?O.text.primary:w.text.primary}var N=function(e){var t=e.color,n=e.name,r=e.mainShade,i=void 0===r?500:r,a=e.lightShade,c=void 0===a?300:a,u=e.darkShade,l=void 0===u?700:u;if(!(t=Object(o.a)({},t)).main&&t[i]&&(t.main=t[i]),!t.hasOwnProperty("main"))throw new Error(Object(s.a)(11,n?" (".concat(n,")"):"",i));if("string"!==typeof t.main)throw new Error(Object(s.a)(12,n?" (".concat(n,")"):"",JSON.stringify(t.main)));return j(t,"light",c,x),j(t,"dark",l,x),t.contrastText||(t.contrastText=T(t.main)),t},R={dark:O,light:w};return Object(a.a)(Object(o.a)({common:f,mode:n,primary:N({color:_,name:"primary"}),secondary:N({color:k,name:"secondary",mainShade:"A400",lightShade:"A200",darkShade:"A700"}),error:N({color:S,name:"error"}),warning:N({color:M,name:"warning"}),info:N({color:C,name:"info"}),success:N({color:P,name:"success"}),grey:d,contrastThreshold:c,getContrastText:T,augmentColor:N,tonalOffset:x},R[n]),E)}var E=["fontFamily","fontSize","fontWeightLight","fontWeightRegular","fontWeightMedium","fontWeightBold","htmlFontSize","allVariants","pxToRem"];var _={textTransform:"uppercase"},k='"Roboto", "Helvetica", "Arial", sans-serif';function S(e,t){var n="function"===typeof t?t(e):t,r=n.fontFamily,c=void 0===r?k:r,u=n.fontSize,s=void 0===u?14:u,l=n.fontWeightLight,f=void 0===l?300:l,d=n.fontWeightRegular,p=void 0===d?400:d,h=n.fontWeightMedium,v=void 0===h?500:h,m=n.fontWeightBold,g=void 0===m?700:m,b=n.htmlFontSize,y=void 0===b?16:b,w=n.allVariants,O=n.pxToRem,j=Object(i.a)(n,E);var x=s/14,S=O||function(e){return"".concat(e/y*x,"rem")},C=function(e,t,n,r,i){return Object(o.a)({fontFamily:c,fontWeight:e,fontSize:S(t),lineHeight:n},c===k?{letterSpacing:"".concat((a=r/t,Math.round(1e5*a)/1e5),"em")}:{},i,w);var a},P={h1:C(f,96,1.167,-1.5),h2:C(f,60,1.2,-.5),h3:C(p,48,1.167,0),h4:C(p,34,1.235,.25),h5:C(p,24,1.334,0),h6:C(v,20,1.6,.15),subtitle1:C(p,16,1.75,.15),subtitle2:C(v,14,1.57,.1),body1:C(p,16,1.5,.15),body2:C(p,14,1.43,.15),button:C(v,14,1.75,.4,_),caption:C(p,12,1.66,.4),overline:C(p,12,2.66,1,_)};return Object(a.a)(Object(o.a)({htmlFontSize:y,pxToRem:S,fontFamily:c,fontSize:s,fontWeightLight:f,fontWeightRegular:p,fontWeightMedium:v,fontWeightBold:g},P),j,{clone:!1})}function C(){return["".concat(arguments.length<=0?void 0:arguments[0],"px ").concat(arguments.length<=1?void 0:arguments[1],"px ").concat(arguments.length<=2?void 0:arguments[2],"px ").concat(arguments.length<=3?void 0:arguments[3],"px rgba(0,0,0,").concat(.2,")"),"".concat(arguments.length<=4?void 0:arguments[4],"px ").concat(arguments.length<=5?void 0:arguments[5],"px ").concat(arguments.length<=6?void 0:arguments[6],"px ").concat(arguments.length<=7?void 0:arguments[7],"px rgba(0,0,0,").concat(.14,")"),"".concat(arguments.length<=8?void 0:arguments[8],"px ").concat(arguments.length<=9?void 0:arguments[9],"px ").concat(arguments.length<=10?void 0:arguments[10],"px ").concat(arguments.length<=11?void 0:arguments[11],"px rgba(0,0,0,").concat(.12,")")].join(",")}var P=["none",C(0,2,1,-1,0,1,1,0,0,1,3,0),C(0,3,1,-2,0,2,2,0,0,1,5,0),C(0,3,3,-2,0,3,4,0,0,1,8,0),C(0,2,4,-1,0,4,5,0,0,1,10,0),C(0,3,5,-1,0,5,8,0,0,1,14,0),C(0,3,5,-1,0,6,10,0,0,1,18,0),C(0,4,5,-2,0,7,10,1,0,2,16,1),C(0,5,5,-3,0,8,10,1,0,3,14,2),C(0,5,6,-3,0,9,12,1,0,3,16,2),C(0,6,6,-3,0,10,14,1,0,4,18,3),C(0,6,7,-4,0,11,15,1,0,4,20,3),C(0,7,8,-4,0,12,17,2,0,5,22,4),C(0,7,8,-4,0,13,19,2,0,5,24,4),C(0,7,9,-4,0,14,21,2,0,5,26,4),C(0,8,9,-5,0,15,22,2,0,6,28,5),C(0,8,10,-5,0,16,24,2,0,6,30,5),C(0,8,11,-5,0,17,26,2,0,6,32,5),C(0,9,11,-5,0,18,28,2,0,7,34,6),C(0,9,12,-6,0,19,29,2,0,7,36,6),C(0,10,13,-6,0,20,31,3,0,8,38,7),C(0,10,13,-6,0,21,33,3,0,8,40,7),C(0,10,14,-6,0,22,35,3,0,8,42,7),C(0,11,14,-7,0,23,36,3,0,9,44,8),C(0,11,15,-7,0,24,38,3,0,9,46,8)],M=n(44),T={mobileStepper:1e3,speedDial:1050,appBar:1100,drawer:1200,modal:1300,snackbar:1400,tooltip:1500},N=["breakpoints","mixins","spacing","palette","transitions","typography","shape"];function R(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.mixins,n=void 0===t?{}:t,r=e.palette,s=void 0===r?{}:r,l=e.transitions,f=void 0===l?{}:l,d=e.typography,p=void 0===d?{}:d,h=Object(i.a)(e,N),v=x(s),m=Object(c.a)(e),g=Object(a.a)(m,{mixins:u(m.breakpoints,m.spacing,n),palette:v,shadows:P.slice(),typography:S(v,p),transitions:Object(M.a)(f),zIndex:Object(o.a)({},T)});g=Object(a.a)(g,h);for(var b=arguments.length,y=new Array(b>1?b-1:0),w=1;w2&&void 0!==arguments[2]?arguments[2]:{clone:!0},a=n.clone?Object(r.a)({},e):e;return o(e)&&o(t)&&Object.keys(t).forEach((function(r){"__proto__"!==r&&(o(t[r])&&r in e&&o(e[r])?a[r]=i(e[r],t[r],n):a[r]=t[r])})),a}},,,,,,function(e,t,n){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;rl))return!1;var d=u.get(e),p=u.get(t);if(d&&p)return d==t&&p==e;var h=-1,v=!0,m=2&n?new r:void 0;for(u.set(e,t),u.set(t,e);++h0&&(i=u.removeMin(),(a=c[i]).distance!==Number.POSITIVE_INFINITY);)r(i).forEach(s);return c}(e,String(t),n||i,r||function(t){return e.outEdges(t)})};var i=r.constant(1)},function(e,t,n){var r=n(46);function o(){this._arr=[],this._keyIndices={}}e.exports=o,o.prototype.size=function(){return this._arr.length},o.prototype.keys=function(){return this._arr.map((function(e){return e.key}))},o.prototype.has=function(e){return r.has(this._keyIndices,e)},o.prototype.priority=function(e){var t=this._keyIndices[e];if(void 0!==t)return this._arr[t].priority},o.prototype.min=function(){if(0===this.size())throw new Error("Queue underflow");return this._arr[0].key},o.prototype.add=function(e,t){var n=this._keyIndices;if(e=String(e),!r.has(n,e)){var o=this._arr,i=o.length;return n[e]=i,o.push({key:e,priority:t}),this._decrease(i),!0}return!1},o.prototype.removeMin=function(){this._swap(0,this._arr.length-1);var e=this._arr.pop();return delete this._keyIndices[e.key],this._heapify(0),e.key},o.prototype.decrease=function(e,t){var n=this._keyIndices[e];if(t>this._arr[n].priority)throw new Error("New priority is greater than current priority. Key: "+e+" Old: "+this._arr[n].priority+" New: "+t);this._arr[n].priority=t,this._decrease(n)},o.prototype._heapify=function(e){var t=this._arr,n=2*e,r=n+1,o=e;n>1].prioritye.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:3,t=new Map,n=Math.pow(10,e);return{get:function(e){var r=e.match(S).length;if(t.has(r))return t.get(r);var o=1/Math.sqrt(r),i=parseFloat(Math.round(o*n)/n);return t.set(r,i),i},clear:function(){t.clear()}}}var P=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.getFn,r=void 0===n?k.getFn:n;Object(u.a)(this,e),this.norm=C(3),this.getFn=r,this.isCreated=!1,this.setIndexRecords()}return Object(s.a)(e,[{key:"setSources",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.docs=e}},{key:"setIndexRecords",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.records=e}},{key:"setKeys",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.keys=t,this._keysMap={},t.forEach((function(t,n){e._keysMap[t.id]=n}))}},{key:"create",value:function(){var e=this;!this.isCreated&&this.docs.length&&(this.isCreated=!0,f(this.docs[0])?this.docs.forEach((function(t,n){e._addString(t,n)})):this.docs.forEach((function(t,n){e._addObject(t,n)})),this.norm.clear())}},{key:"add",value:function(e){var t=this.size();f(e)?this._addString(e,t):this._addObject(e,t)}},{key:"removeAt",value:function(e){this.records.splice(e,1);for(var t=e,n=this.size();t2&&void 0!==arguments[2]?arguments[2]:{},r=n.getFn,o=void 0===r?k.getFn:r,i=new P({getFn:o});return i.setKeys(e.map(j)),i.setSources(t),i.create(),i}function T(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.errors,r=void 0===n?0:n,o=t.currentLocation,i=void 0===o?0:o,a=t.expectedLocation,c=void 0===a?0:a,u=t.distance,s=void 0===u?k.distance:u,l=t.ignoreLocation,f=void 0===l?k.ignoreLocation:l,d=r/e.length;if(f)return d;var p=Math.abs(c-i);return s?d+p/s:p?1:d}function N(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:k.minMatchCharLength,n=[],r=-1,o=-1,i=0,a=e.length;i=t&&n.push([r,o]),r=-1)}return e[i-1]&&i-r>=t&&n.push([r,i-1]),n}var R=32;function A(e){for(var t={},n=0,r=e.length;n1&&void 0!==arguments[1]?arguments[1]:{},o=r.location,i=void 0===o?k.location:o,a=r.threshold,c=void 0===a?k.threshold:a,s=r.distance,l=void 0===s?k.distance:s,f=r.includeMatches,d=void 0===f?k.includeMatches:f,p=r.findAllMatches,h=void 0===p?k.findAllMatches:p,v=r.minMatchCharLength,m=void 0===v?k.minMatchCharLength:v,g=r.isCaseSensitive,b=void 0===g?k.isCaseSensitive:g,y=r.ignoreLocation,w=void 0===y?k.ignoreLocation:y;if(Object(u.a)(this,e),this.options={location:i,threshold:c,distance:l,includeMatches:d,findAllMatches:h,minMatchCharLength:m,isCaseSensitive:b,ignoreLocation:w},this.pattern=b?t:t.toLowerCase(),this.chunks=[],this.pattern.length){var O=function(e,t){n.chunks.push({pattern:e,alphabet:A(e),startIndex:t})},j=this.pattern.length;if(j>R){for(var x=0,E=j%R,_=j-E;x<_;)O(this.pattern.substr(x,R),x),x+=R;if(E){var S=j-R;O(this.pattern.substr(S),S)}}else O(this.pattern,0)}}return Object(s.a)(e,[{key:"searchIn",value:function(e){var t=this.options,n=t.isCaseSensitive,r=t.includeMatches;if(n||(e=e.toLowerCase()),this.pattern===e){var o={isMatch:!0,score:0};return r&&(o.indices=[[0,e.length-1]]),o}var i=this.options,c=i.location,u=i.distance,s=i.threshold,l=i.findAllMatches,f=i.minMatchCharLength,d=i.ignoreLocation,p=[],h=0,v=!1;this.chunks.forEach((function(t){var n=t.pattern,o=t.alphabet,i=t.startIndex,m=function(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=r.location,i=void 0===o?k.location:o,a=r.distance,c=void 0===a?k.distance:a,u=r.threshold,s=void 0===u?k.threshold:u,l=r.findAllMatches,f=void 0===l?k.findAllMatches:l,d=r.minMatchCharLength,p=void 0===d?k.minMatchCharLength:d,h=r.includeMatches,v=void 0===h?k.includeMatches:h,m=r.ignoreLocation,g=void 0===m?k.ignoreLocation:m;if(t.length>R)throw new Error(y(R));for(var b,w=t.length,O=e.length,j=Math.max(0,Math.min(i,O)),x=s,E=j,_=p>1||v,S=_?Array(O):[];(b=e.indexOf(t,E))>-1;){var C=T(t,{currentLocation:b,expectedLocation:j,distance:c,ignoreLocation:g});if(x=Math.min(C,x),E=b+w,_)for(var P=0;P=F;H-=1){var V=H-1,$=n[e.charAt(V)];if(_&&(S[V]=+!!$),W[H]=(W[H+1]<<1|1)&$,D&&(W[H]|=(M[H+1]|M[H])<<1|1|M[H+1]),W[H]&I&&(A=T(t,{errors:D,currentLocation:V,expectedLocation:j,distance:c,ignoreLocation:g}))<=x){if(x=A,(E=V)<=j)break;F=Math.max(1,2*j-E)}}if(T(t,{errors:D+1,currentLocation:j,expectedLocation:j,distance:c,ignoreLocation:g})>x)break;M=W}var Y={isMatch:E>=0,score:Math.max(.001,A)};if(_){var q=N(S,p);q.length?v&&(Y.indices=q):Y.isMatch=!1}return Y}(e,n,o,{location:c+i,distance:u,threshold:s,findAllMatches:l,minMatchCharLength:f,includeMatches:r,ignoreLocation:d}),g=m.isMatch,b=m.score,w=m.indices;g&&(v=!0),h+=b,g&&w&&(p=[].concat(Object(a.a)(p),Object(a.a)(w)))}));var m={isMatch:v,score:v?h/this.chunks.length:1};return v&&r&&(m.indices=p),m}}]),e}(),I=function(){function e(t){Object(u.a)(this,e),this.pattern=t}return Object(s.a)(e,[{key:"search",value:function(){}}],[{key:"isMultiMatch",value:function(e){return D(e,this.multiRegex)}},{key:"isSingleMatch",value:function(e){return D(e,this.singleRegex)}}]),e}();function D(e,t){var n=e.match(t);return n?n[1]:null}var z=function(e){Object(o.a)(n,e);var t=Object(i.a)(n);function n(e){return Object(u.a)(this,n),t.call(this,e)}return Object(s.a)(n,[{key:"search",value:function(e){var t=e===this.pattern;return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"exact"}},{key:"multiRegex",get:function(){return/^="(.*)"$/}},{key:"singleRegex",get:function(){return/^=(.*)$/}}]),n}(I),B=function(e){Object(o.a)(n,e);var t=Object(i.a)(n);function n(e){return Object(u.a)(this,n),t.call(this,e)}return Object(s.a)(n,[{key:"search",value:function(e){var t=-1===e.indexOf(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"$/}},{key:"singleRegex",get:function(){return/^!(.*)$/}}]),n}(I),F=function(e){Object(o.a)(n,e);var t=Object(i.a)(n);function n(e){return Object(u.a)(this,n),t.call(this,e)}return Object(s.a)(n,[{key:"search",value:function(e){var t=e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"prefix-exact"}},{key:"multiRegex",get:function(){return/^\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^\^(.*)$/}}]),n}(I),U=function(e){Object(o.a)(n,e);var t=Object(i.a)(n);function n(e){return Object(u.a)(this,n),t.call(this,e)}return Object(s.a)(n,[{key:"search",value:function(e){var t=!e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-prefix-exact"}},{key:"multiRegex",get:function(){return/^!\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^!\^(.*)$/}}]),n}(I),W=function(e){Object(o.a)(n,e);var t=Object(i.a)(n);function n(e){return Object(u.a)(this,n),t.call(this,e)}return Object(s.a)(n,[{key:"search",value:function(e){var t=e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[e.length-this.pattern.length,e.length-1]}}}],[{key:"type",get:function(){return"suffix-exact"}},{key:"multiRegex",get:function(){return/^"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^(.*)\$$/}}]),n}(I),H=function(e){Object(o.a)(n,e);var t=Object(i.a)(n);function n(e){return Object(u.a)(this,n),t.call(this,e)}return Object(s.a)(n,[{key:"search",value:function(e){var t=!e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-suffix-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^!(.*)\$$/}}]),n}(I),V=function(e){Object(o.a)(n,e);var t=Object(i.a)(n);function n(e){var r,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=o.location,a=void 0===i?k.location:i,c=o.threshold,s=void 0===c?k.threshold:c,l=o.distance,f=void 0===l?k.distance:l,d=o.includeMatches,p=void 0===d?k.includeMatches:d,h=o.findAllMatches,v=void 0===h?k.findAllMatches:h,m=o.minMatchCharLength,g=void 0===m?k.minMatchCharLength:m,b=o.isCaseSensitive,y=void 0===b?k.isCaseSensitive:b,w=o.ignoreLocation,O=void 0===w?k.ignoreLocation:w;return Object(u.a)(this,n),(r=t.call(this,e))._bitapSearch=new L(e,{location:a,threshold:s,distance:f,includeMatches:p,findAllMatches:v,minMatchCharLength:g,isCaseSensitive:y,ignoreLocation:O}),r}return Object(s.a)(n,[{key:"search",value:function(e){return this._bitapSearch.searchIn(e)}}],[{key:"type",get:function(){return"fuzzy"}},{key:"multiRegex",get:function(){return/^"(.*)"$/}},{key:"singleRegex",get:function(){return/^(.*)$/}}]),n}(I),$=function(e){Object(o.a)(n,e);var t=Object(i.a)(n);function n(e){return Object(u.a)(this,n),t.call(this,e)}return Object(s.a)(n,[{key:"search",value:function(e){for(var t,n=0,r=[],o=this.pattern.length;(t=e.indexOf(this.pattern,n))>-1;)n=t+o,r.push([t,n-1]);var i=!!r.length;return{isMatch:i,score:i?0:1,indices:r}}}],[{key:"type",get:function(){return"include"}},{key:"multiRegex",get:function(){return/^'"(.*)"$/}},{key:"singleRegex",get:function(){return/^'(.*)$/}}]),n}(I),Y=[z,$,F,U,H,W,B,V],q=Y.length,X=/ +(?=([^\"]*\"[^\"]*\")*[^\"]*$)/;function K(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.split("|").map((function(e){for(var n=e.trim().split(X).filter((function(e){return e&&!!e.trim()})),r=[],o=0,i=n.length;o1&&void 0!==arguments[1]?arguments[1]:{},r=n.isCaseSensitive,o=void 0===r?k.isCaseSensitive:r,i=n.includeMatches,a=void 0===i?k.includeMatches:i,c=n.minMatchCharLength,s=void 0===c?k.minMatchCharLength:c,l=n.ignoreLocation,f=void 0===l?k.ignoreLocation:l,d=n.findAllMatches,p=void 0===d?k.findAllMatches:d,h=n.location,v=void 0===h?k.location:h,m=n.threshold,g=void 0===m?k.threshold:m,b=n.distance,y=void 0===b?k.distance:b;Object(u.a)(this,e),this.query=null,this.options={isCaseSensitive:o,includeMatches:a,minMatchCharLength:s,findAllMatches:p,ignoreLocation:f,location:v,threshold:g,distance:y},this.pattern=o?t:t.toLowerCase(),this.query=K(this.pattern,this.options)}return Object(s.a)(e,[{key:"searchIn",value:function(e){var t=this.query;if(!t)return{isMatch:!1,score:1};var n=this.options,r=n.includeMatches;e=n.isCaseSensitive?e:e.toLowerCase();for(var o=0,i=[],c=0,u=0,s=t.length;u2&&void 0!==arguments[2]?arguments[2]:{},r=n.auto,o=void 0===r||r,i=function e(n){var r=Object.keys(n),i=ie(n);if(!i&&r.length>1&&!oe(n))return e(ce(n));if(ae(n)){var a=i?n[ne]:r[0],c=i?n[re]:n[a];if(!f(c))throw new Error(b(a));var u={keyId:E(a),pattern:c};return o&&(u.searcher=J(c,t)),u}var s={children:[],operator:r[0]};return r.forEach((function(t){var r=n[t];l(r)&&r.forEach((function(t){s.children.push(e(t))}))})),s};return oe(e)||(e=ce(e)),i(e)}function se(e,t){var n=t.ignoreFieldNorm,r=void 0===n?k.ignoreFieldNorm:n;e.forEach((function(e){var t=1;e.matches.forEach((function(e){var n=e.key,o=e.norm,i=e.score,a=n?n.weight:null;t*=Math.pow(0===i&&a?Number.EPSILON:i,(a||1)*(r?1:o))})),e.score=t}))}function le(e,t){var n=e.matches;t.matches=[],v(n)&&n.forEach((function(e){if(v(e.indices)&&e.indices.length){var n={indices:e.indices,value:e.value};e.key&&(n.key=e.key.src),e.idx>-1&&(n.refIndex=e.idx),t.matches.push(n)}}))}function fe(e,t){t.score=e.score}function de(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.includeMatches,o=void 0===r?k.includeMatches:r,i=n.includeScore,a=void 0===i?k.includeScore:i,c=[];return o&&c.push(le),a&&c.push(fe),e.map((function(e){var n=e.idx,r={item:t[n],refIndex:n};return c.length&&c.forEach((function(t){t(e,r)})),r}))}var pe=function(){function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=arguments.length>2?arguments[2]:void 0;Object(u.a)(this,e),this.options=Object(c.a)(Object(c.a)({},k),n),this.options.useExtendedSearch,this._keyStore=new O(this.options.keys),this.setCollection(t,r)}return Object(s.a)(e,[{key:"setCollection",value:function(e,t){if(this._docs=e,t&&!(t instanceof P))throw new Error("Incorrect 'index' type");this._myIndex=t||M(this.options.keys,this._docs,{getFn:this.options.getFn})}},{key:"add",value:function(e){v(e)&&(this._docs.push(e),this._myIndex.add(e))}},{key:"remove",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!1},t=[],n=0,r=this._docs.length;n1&&void 0!==arguments[1]?arguments[1]:{},n=t.limit,r=void 0===n?-1:n,o=this.options,i=o.includeMatches,a=o.includeScore,c=o.shouldSort,u=o.sortFn,s=o.ignoreFieldNorm,l=f(e)?f(this._docs[0])?this._searchStringList(e):this._searchObjectList(e):this._searchLogical(e);return se(l,{ignoreFieldNorm:s}),c&&l.sort(u),d(r)&&r>-1&&(l=l.slice(0,r)),de(l,this._docs,{includeMatches:i,includeScore:a})}},{key:"_searchStringList",value:function(e){var t=J(e,this.options),n=this._myIndex.records,r=[];return n.forEach((function(e){var n=e.v,o=e.i,i=e.n;if(v(n)){var a=t.searchIn(n),c=a.isMatch,u=a.score,s=a.indices;c&&r.push({item:n,idx:o,matches:[{score:u,value:n,norm:i,indices:s}]})}})),r}},{key:"_searchLogical",value:function(e){var t=this,n=ue(e,this.options),r=function e(n,r,o){if(!n.children){var i=n.keyId,c=n.searcher,u=t._findMatches({key:t._keyStore.get(i),value:t._myIndex.getValueForItemAtKeyId(r,i),searcher:c});return u&&u.length?[{idx:o,item:r,matches:u}]:[]}switch(n.operator){case ee:for(var s=[],l=0,f=n.children.length;l1&&void 0!==arguments[1]?arguments[1]:{},n=t.getFn,r=void 0===n?k.getFn:n,o=e.keys,i=e.records,a=new P({getFn:r});return a.setKeys(o),a.setIndexRecords(i),a},pe.config=k,pe.parseQuery=ue,function(){Z.push.apply(Z,arguments)}(Q),t.a=pe},function(e,t,n){"use strict";function r(e){if("undefined"!==typeof Symbol&&Symbol.iterator in Object(e))return Array.from(e)}n.d(t,"a",(function(){return r}))},function(e,t,n){e.exports=n(311)},function(e,t,n){"use strict";var r=n(329),o={"text/plain":"Text","text/html":"Url",default:"Text"};e.exports=function(e,t){var n,i,a,c,u,s,l=!1;t||(t={}),n=t.debug||!1;try{if(a=r(),c=document.createRange(),u=document.getSelection(),(s=document.createElement("span")).textContent=e,s.style.all="unset",s.style.position="fixed",s.style.top=0,s.style.clip="rect(0, 0, 0, 0)",s.style.whiteSpace="pre",s.style.webkitUserSelect="text",s.style.MozUserSelect="text",s.style.msUserSelect="text",s.style.userSelect="text",s.addEventListener("copy",(function(r){if(r.stopPropagation(),t.format)if(r.preventDefault(),"undefined"===typeof r.clipboardData){n&&console.warn("unable to use e.clipboardData"),n&&console.warn("trying IE specific stuff"),window.clipboardData.clearData();var i=o[t.format]||o.default;window.clipboardData.setData(i,e)}else r.clipboardData.clearData(),r.clipboardData.setData(t.format,e);t.onCopy&&(r.preventDefault(),t.onCopy(r.clipboardData))})),document.body.appendChild(s),c.selectNodeContents(s),u.addRange(c),!document.execCommand("copy"))throw new Error("copy command was unsuccessful");l=!0}catch(f){n&&console.error("unable to copy using execCommand: ",f),n&&console.warn("trying IE specific stuff");try{window.clipboardData.setData(t.format||"text",e),t.onCopy&&t.onCopy(window.clipboardData),l=!0}catch(f){n&&console.error("unable to copy using clipboardData: ",f),n&&console.error("falling back to prompt"),i=function(e){var t=(/mac os x/i.test(navigator.userAgent)?"\u2318":"Ctrl")+"+C";return e.replace(/#{\s*key\s*}/g,t)}("message"in t?t.message:"Copy to clipboard: #{key}, Enter"),window.prompt(i,e)}}finally{u&&("function"==typeof u.removeRange?u.removeRange(c):u.removeAllRanges()),s&&document.body.removeChild(s),a()}return l}},function(e,t,n){"use strict";var r=n(547);function o(e){return 0===Object.keys(e).length}t.a=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=Object(r.a)();return!t||o(t)?e:t}},function(e,t,n){var r;!function(){var o={y:function(e){return 1===e?"\u03c7\u03c1\u03cc\u03bd\u03bf\u03c2":"\u03c7\u03c1\u03cc\u03bd\u03b9\u03b1"},mo:function(e){return 1===e?"\u03bc\u03ae\u03bd\u03b1\u03c2":"\u03bc\u03ae\u03bd\u03b5\u03c2"},w:function(e){return 1===e?"\u03b5\u03b2\u03b4\u03bf\u03bc\u03ac\u03b4\u03b1":"\u03b5\u03b2\u03b4\u03bf\u03bc\u03ac\u03b4\u03b5\u03c2"},d:function(e){return 1===e?"\u03bc\u03ad\u03c1\u03b1":"\u03bc\u03ad\u03c1\u03b5\u03c2"},h:function(e){return 1===e?"\u03ce\u03c1\u03b1":"\u03ce\u03c1\u03b5\u03c2"},m:function(e){return 1===e?"\u03bb\u03b5\u03c0\u03c4\u03cc":"\u03bb\u03b5\u03c0\u03c4\u03ac"},s:function(e){return 1===e?"\u03b4\u03b5\u03c5\u03c4\u03b5\u03c1\u03cc\u03bb\u03b5\u03c0\u03c4\u03bf":"\u03b4\u03b5\u03c5\u03c4\u03b5\u03c1\u03cc\u03bb\u03b5\u03c0\u03c4\u03b1"},ms:function(e){return 1===e?"\u03c7\u03b9\u03bb\u03b9\u03bf\u03c3\u03c4\u03cc \u03c4\u03bf\u03c5 \u03b4\u03b5\u03c5\u03c4\u03b5\u03c1\u03bf\u03bb\u03ad\u03c0\u03c4\u03bf\u03c5":"\u03c7\u03b9\u03bb\u03b9\u03bf\u03c3\u03c4\u03ac \u03c4\u03bf\u03c5 \u03b4\u03b5\u03c5\u03c4\u03b5\u03c1\u03bf\u03bb\u03ad\u03c0\u03c4\u03bf\u03c5"},decimal:","},i=["\u06f0","\u0661","\u0662","\u0663","\u0664","\u0665","\u0666","\u0667","\u0668","\u0669"],a={af:{y:"jaar",mo:function(e){return"maand"+(1===e?"":"e")},w:function(e){return 1===e?"week":"weke"},d:function(e){return 1===e?"dag":"dae"},h:function(e){return 1===e?"uur":"ure"},m:function(e){return 1===e?"minuut":"minute"},s:function(e){return"sekonde"+(1===e?"":"s")},ms:function(e){return"millisekonde"+(1===e?"":"s")},decimal:","},ar:{y:function(e){return["\u0633\u0646\u0629","\u0633\u0646\u062a\u0627\u0646","\u0633\u0646\u0648\u0627\u062a"][f(e)]},mo:function(e){return["\u0634\u0647\u0631","\u0634\u0647\u0631\u0627\u0646","\u0623\u0634\u0647\u0631"][f(e)]},w:function(e){return["\u0623\u0633\u0628\u0648\u0639","\u0623\u0633\u0628\u0648\u0639\u064a\u0646","\u0623\u0633\u0627\u0628\u064a\u0639"][f(e)]},d:function(e){return["\u064a\u0648\u0645","\u064a\u0648\u0645\u064a\u0646","\u0623\u064a\u0627\u0645"][f(e)]},h:function(e){return["\u0633\u0627\u0639\u0629","\u0633\u0627\u0639\u062a\u064a\u0646","\u0633\u0627\u0639\u0627\u062a"][f(e)]},m:function(e){return["\u062f\u0642\u064a\u0642\u0629","\u062f\u0642\u064a\u0642\u062a\u0627\u0646","\u062f\u0642\u0627\u0626\u0642"][f(e)]},s:function(e){return["\u062b\u0627\u0646\u064a\u0629","\u062b\u0627\u0646\u064a\u062a\u0627\u0646","\u062b\u0648\u0627\u0646\u064a"][f(e)]},ms:function(e){return["\u062c\u0632\u0621 \u0645\u0646 \u0627\u0644\u062b\u0627\u0646\u064a\u0629","\u062c\u0632\u0622\u0646 \u0645\u0646 \u0627\u0644\u062b\u0627\u0646\u064a\u0629","\u0623\u062c\u0632\u0627\u0621 \u0645\u0646 \u0627\u0644\u062b\u0627\u0646\u064a\u0629"][f(e)]},decimal:",",delimiter:" \u0648 ",_formatCount:function(e,t){for(var n=l(i,{".":t}),r=e.toString().split(""),o=0;o=2?"s":"")},mo:"mois",w:function(e){return"semaine"+(e>=2?"s":"")},d:function(e){return"jour"+(e>=2?"s":"")},h:function(e){return"heure"+(e>=2?"s":"")},m:function(e){return"minute"+(e>=2?"s":"")},s:function(e){return"seconde"+(e>=2?"s":"")},ms:function(e){return"milliseconde"+(e>=2?"s":"")},decimal:","},gr:o,he:{y:function(e){return 1===e?"\u05e9\u05e0\u05d4":"\u05e9\u05e0\u05d9\u05dd"},mo:function(e){return 1===e?"\u05d7\u05d5\u05d3\u05e9":"\u05d7\u05d5\u05d3\u05e9\u05d9\u05dd"},w:function(e){return 1===e?"\u05e9\u05d1\u05d5\u05e2":"\u05e9\u05d1\u05d5\u05e2\u05d5\u05ea"},d:function(e){return 1===e?"\u05d9\u05d5\u05dd":"\u05d9\u05de\u05d9\u05dd"},h:function(e){return 1===e?"\u05e9\u05e2\u05d4":"\u05e9\u05e2\u05d5\u05ea"},m:function(e){return 1===e?"\u05d3\u05e7\u05d4":"\u05d3\u05e7\u05d5\u05ea"},s:function(e){return 1===e?"\u05e9\u05e0\u05d9\u05d4":"\u05e9\u05e0\u05d9\u05d5\u05ea"},ms:function(e){return 1===e?"\u05de\u05d9\u05dc\u05d9\u05e9\u05e0\u05d9\u05d9\u05d4":"\u05de\u05d9\u05dc\u05d9\u05e9\u05e0\u05d9\u05d5\u05ea"},decimal:"."},hr:{y:function(e){return e%10===2||e%10===3||e%10===4?"godine":"godina"},mo:function(e){return 1===e?"mjesec":2===e||3===e||4===e?"mjeseca":"mjeseci"},w:function(e){return e%10===1&&11!==e?"tjedan":"tjedna"},d:function(e){return 1===e?"dan":"dana"},h:function(e){return 1===e?"sat":2===e||3===e||4===e?"sata":"sati"},m:function(e){var t=e%10;return 2!==t&&3!==t&&4!==t||!(e<10||e>14)?"minuta":"minute"},s:function(e){var t=e%10;return 5===t||Math.floor(e)===e&&e>=10&&e<=19?"sekundi":1===t?"sekunda":2===t||3===t||4===t?"sekunde":"sekundi"},ms:function(e){return 1===e?"milisekunda":e%10===2||e%10===3||e%10===4?"milisekunde":"milisekundi"},decimal:","},hi:{y:"\u0938\u093e\u0932",mo:function(e){return 1===e?"\u092e\u0939\u0940\u0928\u093e":"\u092e\u0939\u0940\u0928\u0947"},w:function(e){return 1===e?"\u0939\u095e\u094d\u0924\u093e":"\u0939\u092b\u094d\u0924\u0947"},d:"\u0926\u093f\u0928",h:function(e){return 1===e?"\u0918\u0902\u091f\u093e":"\u0918\u0902\u091f\u0947"},m:"\u092e\u093f\u0928\u091f",s:"\u0938\u0947\u0915\u0902\u0921",ms:"\u092e\u093f\u0932\u0940\u0938\u0947\u0915\u0902\u0921",decimal:"."},hu:{y:"\xe9v",mo:"h\xf3nap",w:"h\xe9t",d:"nap",h:"\xf3ra",m:"perc",s:"m\xe1sodperc",ms:"ezredm\xe1sodperc",decimal:","},id:{y:"tahun",mo:"bulan",w:"minggu",d:"hari",h:"jam",m:"menit",s:"detik",ms:"milidetik",decimal:"."},is:{y:"\xe1r",mo:function(e){return"m\xe1nu\xf0"+(1===e?"ur":"ir")},w:function(e){return"vik"+(1===e?"a":"ur")},d:function(e){return"dag"+(1===e?"ur":"ar")},h:function(e){return"klukkut\xedm"+(1===e?"i":"ar")},m:function(e){return"m\xedn\xfat"+(1===e?"a":"ur")},s:function(e){return"sek\xfand"+(1===e?"a":"ur")},ms:function(e){return"millisek\xfand"+(1===e?"a":"ur")},decimal:"."},it:{y:function(e){return"ann"+(1===e?"o":"i")},mo:function(e){return"mes"+(1===e?"e":"i")},w:function(e){return"settiman"+(1===e?"a":"e")},d:function(e){return"giorn"+(1===e?"o":"i")},h:function(e){return"or"+(1===e?"a":"e")},m:function(e){return"minut"+(1===e?"o":"i")},s:function(e){return"second"+(1===e?"o":"i")},ms:function(e){return"millisecond"+(1===e?"o":"i")},decimal:","},ja:{y:"\u5e74",mo:"\u30f6\u6708",w:"\u9031",d:"\u65e5",h:"\u6642\u9593",m:"\u5206",s:"\u79d2",ms:"\u30df\u30ea\u79d2",decimal:"."},km:{y:"\u1786\u17d2\u1793\u17b6\u17c6",mo:"\u1781\u17c2",w:"\u179f\u1794\u17d2\u178f\u17b6\u17a0\u17cd",d:"\u1790\u17d2\u1784\u17c3",h:"\u1798\u17c9\u17c4\u1784",m:"\u1793\u17b6\u1791\u17b8",s:"\u179c\u17b7\u1793\u17b6\u1791\u17b8",ms:"\u1798\u17b7\u179b\u17d2\u179b\u17b8\u179c\u17b7\u1793\u17b6\u1791\u17b8"},kn:{y:function(e){return 1===e?"\u0cb5\u0cb0\u0ccd\u0cb7":"\u0cb5\u0cb0\u0ccd\u0cb7\u0c97\u0cb3\u0cc1"},mo:function(e){return 1===e?"\u0ca4\u0cbf\u0c82\u0c97\u0cb3\u0cc1":"\u0ca4\u0cbf\u0c82\u0c97\u0cb3\u0cc1\u0c97\u0cb3\u0cc1"},w:function(e){return 1===e?"\u0cb5\u0cbe\u0cb0":"\u0cb5\u0cbe\u0cb0\u0c97\u0cb3\u0cc1"},d:function(e){return 1===e?"\u0ca6\u0cbf\u0ca8":"\u0ca6\u0cbf\u0ca8\u0c97\u0cb3\u0cc1"},h:function(e){return 1===e?"\u0c97\u0c82\u0c9f\u0cc6":"\u0c97\u0c82\u0c9f\u0cc6\u0c97\u0cb3\u0cc1"},m:function(e){return 1===e?"\u0ca8\u0cbf\u0cae\u0cbf\u0cb7":"\u0ca8\u0cbf\u0cae\u0cbf\u0cb7\u0c97\u0cb3\u0cc1"},s:function(e){return 1===e?"\u0cb8\u0cc6\u0c95\u0cc6\u0c82\u0ca1\u0ccd":"\u0cb8\u0cc6\u0c95\u0cc6\u0c82\u0ca1\u0cc1\u0c97\u0cb3\u0cc1"},ms:function(e){return 1===e?"\u0cae\u0cbf\u0cb2\u0cbf\u0cb8\u0cc6\u0c95\u0cc6\u0c82\u0ca1\u0ccd":"\u0cae\u0cbf\u0cb2\u0cbf\u0cb8\u0cc6\u0c95\u0cc6\u0c82\u0ca1\u0cc1\u0c97\u0cb3\u0cc1"}},ko:{y:"\ub144",mo:"\uac1c\uc6d4",w:"\uc8fc\uc77c",d:"\uc77c",h:"\uc2dc\uac04",m:"\ubd84",s:"\ucd08",ms:"\ubc00\ub9ac \ucd08",decimal:"."},ku:{y:"sal",mo:"meh",w:"hefte",d:"roj",h:"seet",m:"deqe",s:"saniye",ms:"m\xeel\xee\xe7irk",decimal:","},lo:{y:"\u0e9b\u0eb5",mo:"\u0ec0\u0e94\u0eb7\u0ead\u0e99",w:"\u0ead\u0eb2\u0e97\u0eb4\u0e94",d:"\u0ea1\u0eb7\u0ec9",h:"\u0e8a\u0ebb\u0ec8\u0ea7\u0ec2\u0ea1\u0e87",m:"\u0e99\u0eb2\u0e97\u0eb5",s:"\u0ea7\u0eb4\u0e99\u0eb2\u0e97\u0eb5",ms:"\u0ea1\u0eb4\u0e99\u0ea5\u0eb4\u0ea7\u0eb4\u0e99\u0eb2\u0e97\u0eb5",decimal:","},lt:{y:function(e){return e%10===0||e%100>=10&&e%100<=20?"met\u0173":"metai"},mo:function(e){return["m\u0117nuo","m\u0117nesiai","m\u0117nesi\u0173"][v(e)]},w:function(e){return["savait\u0117","savait\u0117s","savai\u010di\u0173"][v(e)]},d:function(e){return["diena","dienos","dien\u0173"][v(e)]},h:function(e){return["valanda","valandos","valand\u0173"][v(e)]},m:function(e){return["minut\u0117","minut\u0117s","minu\u010di\u0173"][v(e)]},s:function(e){return["sekund\u0117","sekund\u0117s","sekund\u017ei\u0173"][v(e)]},ms:function(e){return["milisekund\u0117","milisekund\u0117s","milisekund\u017ei\u0173"][v(e)]},decimal:","},lv:{y:function(e){return m(e)?"gads":"gadi"},mo:function(e){return m(e)?"m\u0113nesis":"m\u0113ne\u0161i"},w:function(e){return m(e)?"ned\u0113\u013ca":"ned\u0113\u013cas"},d:function(e){return m(e)?"diena":"dienas"},h:function(e){return m(e)?"stunda":"stundas"},m:function(e){return m(e)?"min\u016bte":"min\u016btes"},s:function(e){return m(e)?"sekunde":"sekundes"},ms:function(e){return m(e)?"milisekunde":"milisekundes"},decimal:","},mk:{y:function(e){return 1===e?"\u0433\u043e\u0434\u0438\u043d\u0430":"\u0433\u043e\u0434\u0438\u043d\u0438"},mo:function(e){return 1===e?"\u043c\u0435\u0441\u0435\u0446":"\u043c\u0435\u0441\u0435\u0446\u0438"},w:function(e){return 1===e?"\u043d\u0435\u0434\u0435\u043b\u0430":"\u043d\u0435\u0434\u0435\u043b\u0438"},d:function(e){return 1===e?"\u0434\u0435\u043d":"\u0434\u0435\u043d\u0430"},h:function(e){return 1===e?"\u0447\u0430\u0441":"\u0447\u0430\u0441\u0430"},m:function(e){return 1===e?"\u043c\u0438\u043d\u0443\u0442\u0430":"\u043c\u0438\u043d\u0443\u0442\u0438"},s:function(e){return 1===e?"\u0441\u0435\u043a\u0443\u043d\u0434\u0430":"\u0441\u0435\u043a\u0443\u043d\u0434\u0438"},ms:function(e){return 1===e?"\u043c\u0438\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u0430":"\u043c\u0438\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u0438"},decimal:","},mr:{y:function(e){return 1===e?"\u0935\u0930\u094d\u0937":"\u0935\u0930\u094d\u0937\u0947"},mo:function(e){return 1===e?"\u092e\u0939\u093f\u0928\u093e":"\u092e\u0939\u093f\u0928\u0947"},w:function(e){return 1===e?"\u0906\u0920\u0935\u0921\u093e":"\u0906\u0920\u0935\u0921\u0947"},d:"\u0926\u093f\u0935\u0938",h:"\u0924\u093e\u0938",m:function(e){return 1===e?"\u092e\u093f\u0928\u093f\u091f":"\u092e\u093f\u0928\u093f\u091f\u0947"},s:"\u0938\u0947\u0915\u0902\u0926",ms:"\u092e\u093f\u0932\u093f\u0938\u0947\u0915\u0902\u0926"},ms:{y:"tahun",mo:"bulan",w:"minggu",d:"hari",h:"jam",m:"minit",s:"saat",ms:"milisaat",decimal:"."},nl:{y:"jaar",mo:function(e){return 1===e?"maand":"maanden"},w:function(e){return 1===e?"week":"weken"},d:function(e){return 1===e?"dag":"dagen"},h:"uur",m:function(e){return 1===e?"minuut":"minuten"},s:function(e){return 1===e?"seconde":"seconden"},ms:function(e){return 1===e?"milliseconde":"milliseconden"},decimal:","},no:{y:"\xe5r",mo:function(e){return"m\xe5ned"+(1===e?"":"er")},w:function(e){return"uke"+(1===e?"":"r")},d:function(e){return"dag"+(1===e?"":"er")},h:function(e){return"time"+(1===e?"":"r")},m:function(e){return"minutt"+(1===e?"":"er")},s:function(e){return"sekund"+(1===e?"":"er")},ms:function(e){return"millisekund"+(1===e?"":"er")},decimal:","},pl:{y:function(e){return["rok","roku","lata","lat"][d(e)]},mo:function(e){return["miesi\u0105c","miesi\u0105ca","miesi\u0105ce","miesi\u0119cy"][d(e)]},w:function(e){return["tydzie\u0144","tygodnia","tygodnie","tygodni"][d(e)]},d:function(e){return["dzie\u0144","dnia","dni","dni"][d(e)]},h:function(e){return["godzina","godziny","godziny","godzin"][d(e)]},m:function(e){return["minuta","minuty","minuty","minut"][d(e)]},s:function(e){return["sekunda","sekundy","sekundy","sekund"][d(e)]},ms:function(e){return["milisekunda","milisekundy","milisekundy","milisekund"][d(e)]},decimal:","},pt:{y:function(e){return"ano"+(1===e?"":"s")},mo:function(e){return 1===e?"m\xeas":"meses"},w:function(e){return"semana"+(1===e?"":"s")},d:function(e){return"dia"+(1===e?"":"s")},h:function(e){return"hora"+(1===e?"":"s")},m:function(e){return"minuto"+(1===e?"":"s")},s:function(e){return"segundo"+(1===e?"":"s")},ms:function(e){return"milissegundo"+(1===e?"":"s")},decimal:","},ro:{y:function(e){return 1===e?"an":"ani"},mo:function(e){return 1===e?"lun\u0103":"luni"},w:function(e){return 1===e?"s\u0103pt\u0103m\xe2n\u0103":"s\u0103pt\u0103m\xe2ni"},d:function(e){return 1===e?"zi":"zile"},h:function(e){return 1===e?"or\u0103":"ore"},m:function(e){return 1===e?"minut":"minute"},s:function(e){return 1===e?"secund\u0103":"secunde"},ms:function(e){return 1===e?"milisecund\u0103":"milisecunde"},decimal:","},ru:{y:function(e){return["\u043b\u0435\u0442","\u0433\u043e\u0434","\u0433\u043e\u0434\u0430"][p(e)]},mo:function(e){return["\u043c\u0435\u0441\u044f\u0446\u0435\u0432","\u043c\u0435\u0441\u044f\u0446","\u043c\u0435\u0441\u044f\u0446\u0430"][p(e)]},w:function(e){return["\u043d\u0435\u0434\u0435\u043b\u044c","\u043d\u0435\u0434\u0435\u043b\u044f","\u043d\u0435\u0434\u0435\u043b\u0438"][p(e)]},d:function(e){return["\u0434\u043d\u0435\u0439","\u0434\u0435\u043d\u044c","\u0434\u043d\u044f"][p(e)]},h:function(e){return["\u0447\u0430\u0441\u043e\u0432","\u0447\u0430\u0441","\u0447\u0430\u0441\u0430"][p(e)]},m:function(e){return["\u043c\u0438\u043d\u0443\u0442","\u043c\u0438\u043d\u0443\u0442\u0430","\u043c\u0438\u043d\u0443\u0442\u044b"][p(e)]},s:function(e){return["\u0441\u0435\u043a\u0443\u043d\u0434","\u0441\u0435\u043a\u0443\u043d\u0434\u0430","\u0441\u0435\u043a\u0443\u043d\u0434\u044b"][p(e)]},ms:function(e){return["\u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434","\u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u0430","\u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u044b"][p(e)]},decimal:","},sq:{y:function(e){return 1===e?"vit":"vjet"},mo:"muaj",w:"jav\xeb",d:"dit\xeb",h:"or\xeb",m:function(e){return"minut"+(1===e?"\xeb":"a")},s:function(e){return"sekond"+(1===e?"\xeb":"a")},ms:function(e){return"milisekond"+(1===e?"\xeb":"a")},decimal:","},sr:{y:function(e){return["\u0433\u043e\u0434\u0438\u043d\u0438","\u0433\u043e\u0434\u0438\u043d\u0430","\u0433\u043e\u0434\u0438\u043d\u0435"][p(e)]},mo:function(e){return["\u043c\u0435\u0441\u0435\u0446\u0438","\u043c\u0435\u0441\u0435\u0446","\u043c\u0435\u0441\u0435\u0446\u0430"][p(e)]},w:function(e){return["\u043d\u0435\u0434\u0435\u0459\u0438","\u043d\u0435\u0434\u0435\u0459\u0430","\u043d\u0435\u0434\u0435\u0459\u0435"][p(e)]},d:function(e){return["\u0434\u0430\u043d\u0438","\u0434\u0430\u043d","\u0434\u0430\u043d\u0430"][p(e)]},h:function(e){return["\u0441\u0430\u0442\u0438","\u0441\u0430\u0442","\u0441\u0430\u0442\u0430"][p(e)]},m:function(e){return["\u043c\u0438\u043d\u0443\u0442\u0430","\u043c\u0438\u043d\u0443\u0442","\u043c\u0438\u043d\u0443\u0442\u0430"][p(e)]},s:function(e){return["\u0441\u0435\u043a\u0443\u043d\u0434\u0438","\u0441\u0435\u043a\u0443\u043d\u0434\u0430","\u0441\u0435\u043a\u0443\u043d\u0434\u0435"][p(e)]},ms:function(e){return["\u043c\u0438\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u0438","\u043c\u0438\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u0430","\u043c\u0438\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u0435"][p(e)]},decimal:","},ta:{y:function(e){return 1===e?"\u0bb5\u0bb0\u0bc1\u0b9f\u0bae\u0bcd":"\u0b86\u0ba3\u0bcd\u0b9f\u0bc1\u0b95\u0bb3\u0bcd"},mo:function(e){return 1===e?"\u0bae\u0bbe\u0ba4\u0bae\u0bcd":"\u0bae\u0bbe\u0ba4\u0b99\u0bcd\u0b95\u0bb3\u0bcd"},w:function(e){return 1===e?"\u0bb5\u0bbe\u0bb0\u0bae\u0bcd":"\u0bb5\u0bbe\u0bb0\u0b99\u0bcd\u0b95\u0bb3\u0bcd"},d:function(e){return 1===e?"\u0ba8\u0bbe\u0bb3\u0bcd":"\u0ba8\u0bbe\u0b9f\u0bcd\u0b95\u0bb3\u0bcd"},h:function(e){return 1===e?"\u0bae\u0ba3\u0bbf":"\u0bae\u0ba3\u0bbf\u0ba8\u0bc7\u0bb0\u0bae\u0bcd"},m:function(e){return"\u0ba8\u0bbf\u0bae\u0bbf\u0b9f"+(1===e?"\u0bae\u0bcd":"\u0b99\u0bcd\u0b95\u0bb3\u0bcd")},s:function(e){return"\u0bb5\u0bbf\u0ba9\u0bbe\u0b9f\u0bbf"+(1===e?"":"\u0b95\u0bb3\u0bcd")},ms:function(e){return"\u0bae\u0bbf\u0bb2\u0bcd\u0bb2\u0bbf \u0bb5\u0bbf\u0ba8\u0bbe\u0b9f\u0bbf"+(1===e?"":"\u0b95\u0bb3\u0bcd")}},te:{y:function(e){return"\u0c38\u0c02\u0c35\u0c24\u0c4d\u0c38"+(1===e?"\u0c30\u0c02":"\u0c30\u0c3e\u0c32")},mo:function(e){return"\u0c28\u0c46\u0c32"+(1===e?"":"\u0c32")},w:function(e){return 1===e?"\u0c35\u0c3e\u0c30\u0c02":"\u0c35\u0c3e\u0c30\u0c3e\u0c32\u0c41"},d:function(e){return"\u0c30\u0c4b\u0c1c\u0c41"+(1===e?"":"\u0c32\u0c41")},h:function(e){return"\u0c17\u0c02\u0c1f"+(1===e?"":"\u0c32\u0c41")},m:function(e){return 1===e?"\u0c28\u0c3f\u0c2e\u0c3f\u0c37\u0c02":"\u0c28\u0c3f\u0c2e\u0c3f\u0c37\u0c3e\u0c32\u0c41"},s:function(e){return 1===e?"\u0c38\u0c46\u0c15\u0c28\u0c41":"\u0c38\u0c46\u0c15\u0c28\u0c4d\u0c32\u0c41"},ms:function(e){return 1===e?"\u0c2e\u0c3f\u0c32\u0c4d\u0c32\u0c40\u0c38\u0c46\u0c15\u0c28\u0c4d":"\u0c2e\u0c3f\u0c32\u0c4d\u0c32\u0c40\u0c38\u0c46\u0c15\u0c28\u0c4d\u0c32\u0c41"}},uk:{y:function(e){return["\u0440\u043e\u043a\u0456\u0432","\u0440\u0456\u043a","\u0440\u043e\u043a\u0438"][p(e)]},mo:function(e){return["\u043c\u0456\u0441\u044f\u0446\u0456\u0432","\u043c\u0456\u0441\u044f\u0446\u044c","\u043c\u0456\u0441\u044f\u0446\u0456"][p(e)]},w:function(e){return["\u0442\u0438\u0436\u043d\u0456\u0432","\u0442\u0438\u0436\u0434\u0435\u043d\u044c","\u0442\u0438\u0436\u043d\u0456"][p(e)]},d:function(e){return["\u0434\u043d\u0456\u0432","\u0434\u0435\u043d\u044c","\u0434\u043d\u0456"][p(e)]},h:function(e){return["\u0433\u043e\u0434\u0438\u043d","\u0433\u043e\u0434\u0438\u043d\u0430","\u0433\u043e\u0434\u0438\u043d\u0438"][p(e)]},m:function(e){return["\u0445\u0432\u0438\u043b\u0438\u043d","\u0445\u0432\u0438\u043b\u0438\u043d\u0430","\u0445\u0432\u0438\u043b\u0438\u043d\u0438"][p(e)]},s:function(e){return["\u0441\u0435\u043a\u0443\u043d\u0434","\u0441\u0435\u043a\u0443\u043d\u0434\u0430","\u0441\u0435\u043a\u0443\u043d\u0434\u0438"][p(e)]},ms:function(e){return["\u043c\u0456\u043b\u0456\u0441\u0435\u043a\u0443\u043d\u0434","\u043c\u0456\u043b\u0456\u0441\u0435\u043a\u0443\u043d\u0434\u0430","\u043c\u0456\u043b\u0456\u0441\u0435\u043a\u0443\u043d\u0434\u0438"][p(e)]},decimal:","},ur:{y:"\u0633\u0627\u0644",mo:function(e){return 1===e?"\u0645\u06c1\u06cc\u0646\u06c1":"\u0645\u06c1\u06cc\u0646\u06d2"},w:function(e){return 1===e?"\u06c1\u0641\u062a\u06c1":"\u06c1\u0641\u062a\u06d2"},d:"\u062f\u0646",h:function(e){return 1===e?"\u06af\u06be\u0646\u0679\u06c1":"\u06af\u06be\u0646\u0679\u06d2"},m:"\u0645\u0646\u0679",s:"\u0633\u06cc\u06a9\u0646\u0688",ms:"\u0645\u0644\u06cc \u0633\u06cc\u06a9\u0646\u0688",decimal:"."},sk:{y:function(e){return["rok","roky","roky","rokov"][h(e)]},mo:function(e){return["mesiac","mesiace","mesiace","mesiacov"][h(e)]},w:function(e){return["t\xfd\u017ede\u0148","t\xfd\u017edne","t\xfd\u017edne","t\xfd\u017ed\u0148ov"][h(e)]},d:function(e){return["de\u0148","dni","dni","dn\xed"][h(e)]},h:function(e){return["hodina","hodiny","hodiny","hod\xedn"][h(e)]},m:function(e){return["min\xfata","min\xfaty","min\xfaty","min\xfat"][h(e)]},s:function(e){return["sekunda","sekundy","sekundy","sek\xfand"][h(e)]},ms:function(e){return["milisekunda","milisekundy","milisekundy","milisek\xfand"][h(e)]},decimal:","},sl:{y:function(e){return e%10===1?"leto":e%100===2?"leti":e%100===3||e%100===4||Math.floor(e)!==e&&e%100<=5?"leta":"let"},mo:function(e){return e%10===1?"mesec":e%100===2||Math.floor(e)!==e&&e%100<=5?"meseca":e%10===3||e%10===4?"mesece":"mesecev"},w:function(e){return e%10===1?"teden":e%10===2||Math.floor(e)!==e&&e%100<=4?"tedna":e%10===3||e%10===4?"tedne":"tednov"},d:function(e){return e%100===1?"dan":"dni"},h:function(e){return e%10===1?"ura":e%100===2?"uri":e%10===3||e%10===4||Math.floor(e)!==e?"ure":"ur"},m:function(e){return e%10===1?"minuta":e%10===2?"minuti":e%10===3||e%10===4||Math.floor(e)!==e&&e%100<=4?"minute":"minut"},s:function(e){return e%10===1?"sekunda":e%100===2?"sekundi":e%100===3||e%100===4||Math.floor(e)!==e?"sekunde":"sekund"},ms:function(e){return e%10===1?"milisekunda":e%100===2?"milisekundi":e%100===3||e%100===4||Math.floor(e)!==e?"milisekunde":"milisekund"},decimal:","},sv:{y:"\xe5r",mo:function(e){return"m\xe5nad"+(1===e?"":"er")},w:function(e){return"veck"+(1===e?"a":"or")},d:function(e){return"dag"+(1===e?"":"ar")},h:function(e){return"timm"+(1===e?"e":"ar")},m:function(e){return"minut"+(1===e?"":"er")},s:function(e){return"sekund"+(1===e?"":"er")},ms:function(e){return"millisekund"+(1===e?"":"er")},decimal:","},sw:{y:function(e){return 1===e?"mwaka":"miaka"},mo:function(e){return 1===e?"mwezi":"miezi"},w:"wiki",d:function(e){return 1===e?"siku":"masiku"},h:function(e){return 1===e?"saa":"masaa"},m:"dakika",s:"sekunde",ms:"milisekunde",decimal:"."},tr:{y:"y\u0131l",mo:"ay",w:"hafta",d:"g\xfcn",h:"saat",m:"dakika",s:"saniye",ms:"milisaniye",decimal:","},th:{y:"\u0e1b\u0e35",mo:"\u0e40\u0e14\u0e37\u0e2d\u0e19",w:"\u0e2a\u0e31\u0e1b\u0e14\u0e32\u0e2b\u0e4c",d:"\u0e27\u0e31\u0e19",h:"\u0e0a\u0e31\u0e48\u0e27\u0e42\u0e21\u0e07",m:"\u0e19\u0e32\u0e17\u0e35",s:"\u0e27\u0e34\u0e19\u0e32\u0e17\u0e35",ms:"\u0e21\u0e34\u0e25\u0e25\u0e34\u0e27\u0e34\u0e19\u0e32\u0e17\u0e35",decimal:"."},vi:{y:"n\u0103m",mo:"th\xe1ng",w:"tu\u1ea7n",d:"ng\xe0y",h:"gi\u1edd",m:"ph\xfat",s:"gi\xe2y",ms:"mili gi\xe2y",decimal:","},zh_CN:{y:"\u5e74",mo:"\u4e2a\u6708",w:"\u5468",d:"\u5929",h:"\u5c0f\u65f6",m:"\u5206\u949f",s:"\u79d2",ms:"\u6beb\u79d2",decimal:"."},zh_TW:{y:"\u5e74",mo:"\u500b\u6708",w:"\u5468",d:"\u5929",h:"\u5c0f\u6642",m:"\u5206\u9418",s:"\u79d2",ms:"\u6beb\u79d2",decimal:"."}};function c(e){var t=function(e,n){return function(e,t){var n,r,o;e=Math.abs(e);var i,c,u,l=function(e){var t=[e.language];if(b(e,"fallbacks")){if(!g(e.fallbacks)||!e.fallbacks.length)throw new Error("fallbacks must be an array with at least one element");t=t.concat(e.fallbacks)}for(var n=0;n=0&&((o=f[n]).unitCount=Math.round(o.unitCount),0!==n);n--)v=f[n-1],h=t.unitMeasures[v.unitName]/t.unitMeasures[o.unitName],(o.unitCount%h===0||t.largest&&t.largest-12)return y.slice(0,-1).join(w)+(t.serialComma?",":"")+t.conjunction+y.slice(-1)}(e,l({},t,n||{}))};return l(t,{language:"en",spacer:" ",conjunction:"",serialComma:!0,units:["y","mo","w","d","h","m","s"],languages:{},round:!1,unitMeasures:{y:315576e5,mo:26298e5,w:6048e5,d:864e5,h:36e5,m:6e4,s:1e3,ms:1}},e)}var u=c({});function s(e,t,n,r){var o,i;o=b(r,"decimal")?r.decimal:b(n,"decimal")?n.decimal:".",i="function"===typeof n._formatCount?n._formatCount(e,o):e.toString().replace(".",o);var a,c=n[t];return a="function"===typeof c?c(e):c,i+r.spacer+a}function l(e){for(var t,n=1;n2&&e<11?2:0}function d(e){return 1===e?0:Math.floor(e)!==e?1:e%10>=2&&e%10<=4&&!(e%100>10&&e%100<20)?2:3}function p(e){return Math.floor(e)!==e?2:e%100>=5&&e%100<=20||e%10>=5&&e%10<=9||e%10===0?0:e%10===1?1:e>1?2:0}function h(e){return 1===e?0:Math.floor(e)!==e?1:e%10>=2&&e%10<=4&&e%100<10?2:3}function v(e){return 1===e||e%10===1&&e%100>20?0:Math.floor(e)!==e||e%10>=2&&e%100>20||e%10>=2&&e%100<10?1:2}function m(e){return e%10===1&&e%100!==11}var g=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)};function b(e,t){return Object.prototype.hasOwnProperty.call(e,t)}u.getSupportedLanguages=function(){var e=[];for(var t in a)b(a,t)&&"gr"!==t&&e.push(t);return e},u.humanizer=c,void 0===(r=function(){return u}.call(t,n,t,e))||(e.exports=r)}()},function(e,t,n){"use strict";n.d(t,"b",(function(){return i}));var r=n(84),o=n(104);function i(e){return Object(r.a)("MuiTableBody",e)}var a=Object(o.a)("MuiTableBody",["root"]);t.a=a},function(e,t,n){"use strict";n.d(t,"b",(function(){return i}));var r=n(84),o=n(104);function i(e){return Object(r.a)("MuiDivider",e)}var a=Object(o.a)("MuiDivider",["root","absolute","fullWidth","inset","middle","flexItem","light","vertical","withChildren","withChildrenVertical","textAlignRight","textAlignLeft","wrapper","wrapperVertical"]);t.a=a},function(e,t,n){var r=n(531);e.exports=function(e,t){if(null==e)return{};var n,o,i=r(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t,n){var r=n(532),o=n(533),i=n(534),a=n(535);e.exports=function(e){return r(e)||o(e)||i(e)||a()},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t){function n(){return e.exports=n=Object.assign||function(e){for(var t=1;t>>|\.\.\.) /},o={className:"subst",begin:/\{/,end:/\}/,keywords:t,illegal:/#/},i={begin:/\{\{/,relevance:0},a={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,n],relevance:10},{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,n],relevance:10},{begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,n,i,o]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,n,i,o]},{begin:/([uU]|[rR])'/,end:/'/,relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/,end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/,contains:[e.BACKSLASH_ESCAPE,i,o]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,i,o]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},c="[0-9](_?[0-9])*",u="(\\b(".concat(c,"))?\\.(").concat(c,")|\\b(").concat(c,")\\."),s={className:"number",relevance:0,variants:[{begin:"(\\b(".concat(c,")|(").concat(u,"))[eE][+-]?(").concat(c,")[jJ]?\\b")},{begin:"(".concat(u,")[jJ]?")},{begin:"\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?\\b"},{begin:"\\b0[bB](_?[01])+[lL]?\\b"},{begin:"\\b0[oO](_?[0-7])+[lL]?\\b"},{begin:"\\b0[xX](_?[0-9a-fA-F])+[lL]?\\b"},{begin:"\\b(".concat(c,")[jJ]\\b")}]},l={className:"comment",begin:r(/# type:/),end:/$/,keywords:t,contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},f={className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:["self",n,s,a,e.HASH_COMMENT_MODE]}]};return o.contains=[a,s,n],{name:"Python",aliases:["py","gyp","ipython"],keywords:t,illegal:/(<\/|->|\?)|=>/,contains:[n,s,{begin:/\bself\b/},{beginKeywords:"if",relevance:0},a,l,e.HASH_COMMENT_MODE,{variants:[{className:"function",beginKeywords:"def"},{className:"class",beginKeywords:"class"}],end:/:/,illegal:/[${=;\n,]/,contains:[e.UNDERSCORE_TITLE_MODE,f,{begin:/->/,endsWithParent:!0,keywords:t}]},{className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[s,f,a]}]}}},function(e,t,n){"use strict";var r=n(277),o=n.n(r);t.a=o.a},function(e,t){e.exports=function(e){var t={literal:"true false null"},n=[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],r=[e.QUOTE_STRING_MODE,e.C_NUMBER_MODE],o={end:",",endsWithParent:!0,excludeEnd:!0,contains:r,keywords:t},i={begin:/\{/,end:/\}/,contains:[{className:"attr",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE],illegal:"\\n"},e.inherit(o,{begin:/:/})].concat(n),illegal:"\\S"},a={begin:"\\[",end:"\\]",contains:[e.inherit(o)],illegal:"\\S"};return r.push(i,a),n.forEach((function(e){r.push(e)})),{name:"JSON",contains:r,keywords:t,illegal:"\\S"}}},function(e,t,n){"use strict";t.a={"hljs-comment":{color:"#969896"},"hljs-quote":{color:"#969896"},"hljs-variable":{color:"#cc6666"},"hljs-template-variable":{color:"#cc6666"},"hljs-tag":{color:"#cc6666"},"hljs-name":{color:"#cc6666"},"hljs-selector-id":{color:"#cc6666"},"hljs-selector-class":{color:"#cc6666"},"hljs-regexp":{color:"#cc6666"},"hljs-deletion":{color:"#cc6666"},"hljs-number":{color:"#de935f"},"hljs-built_in":{color:"#de935f"},"hljs-builtin-name":{color:"#de935f"},"hljs-literal":{color:"#de935f"},"hljs-type":{color:"#de935f"},"hljs-params":{color:"#de935f"},"hljs-meta":{color:"#de935f"},"hljs-link":{color:"#de935f"},"hljs-attribute":{color:"#f0c674"},"hljs-string":{color:"#b5bd68"},"hljs-symbol":{color:"#b5bd68"},"hljs-bullet":{color:"#b5bd68"},"hljs-addition":{color:"#b5bd68"},"hljs-title":{color:"#81a2be"},"hljs-section":{color:"#81a2be"},"hljs-keyword":{color:"#b294bb"},"hljs-selector-tag":{color:"#b294bb"},hljs:{display:"block",overflowX:"auto",background:"#1d1f21",color:"#c5c8c6",padding:"0.5em"},"hljs-emphasis":{fontStyle:"italic"},"hljs-strong":{fontWeight:"bold"}}},function(e,t){try{e.exports="undefined"!==typeof XMLHttpRequest&&"withCredentials"in new XMLHttpRequest}catch(n){e.exports=!1}},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return m}));var r=n(17),o=n(18),i=n(24),a=n(23),c=n(93),u=n(99),s=n.n(u),l=n(151),f=n.n(l),d=n(53),p=n(57),h=n(62),v="undefined"!==typeof navigator&&"string"===typeof navigator.product&&"reactnative"===navigator.product.toLowerCase(),m=function(t){Object(i.a)(c,t);var n=Object(a.a)(c);function c(e){var t;return Object(r.a)(this,c),(t=n.call(this,e)).supportsBinary=!e.forceBase64,t}return Object(o.a)(c,[{key:"name",get:function(){return"websocket"}},{key:"doOpen",value:function(){if(this.check()){var e=this.uri(),t=this.opts.protocols,n=v?{}:Object(d.b)(this.opts,"agent","perMessageDeflate","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","localAddress","protocolVersion","origin","maxPayload","family","checkServerIdentity");this.opts.extraHeaders&&(n.headers=this.opts.extraHeaders);try{this.ws=p.d&&!v?t?new p.a(e,t):new p.a(e):new p.a(e,t,n)}catch(r){return this.emit("error",r)}this.ws.binaryType=this.socket.binaryType||p.b,this.addEventListeners()}}},{key:"addEventListeners",value:function(){var e=this;this.ws.onopen=function(){e.opts.autoUnref&&e.ws._socket.unref(),e.onOpen()},this.ws.onclose=this.onClose.bind(this),this.ws.onmessage=function(t){return e.onData(t.data)},this.ws.onerror=function(t){return e.onError("websocket error",t)}}},{key:"write",value:function(t){var n=this;this.writable=!1;for(var r=function(r){var o=t[r],i=r===t.length-1;Object(h.c)(o,n.supportsBinary,(function(t){var r={};p.d||(o.options&&(r.compress=o.options.compress),n.opts.perMessageDeflate&&("string"===typeof t?e.byteLength(t):t.length)0&&e.jitter<=1?e.jitter:0,this.attempts=0}e.exports=n,n.prototype.duration=function(){var e=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var t=Math.random(),n=Math.floor(t*this.jitter*e);e=0==(1&Math.floor(10*t))?e-n:e+n}return 0|Math.min(e,this.max)},n.prototype.reset=function(){this.attempts=0},n.prototype.setMin=function(e){this.ms=e},n.prototype.setMax=function(e){this.max=e},n.prototype.setJitter=function(e){this.jitter=e}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=Object.assign||function(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:{};return Object.assign(e,{xd:this.xd,xs:this.xs},this.opts),new S(this.uri(),e)}},{key:"doWrite",value:function(e,t){var n=this,r=this.request({method:"POST",data:e});r.on("success",t),r.on("error",(function(e){n.onError("xhr post error",e)}))}},{key:"doPoll",value:function(){var e=this,t=this.request();t.on("data",this.onData.bind(this)),t.on("error",(function(t){e.onError("xhr poll error",t)})),this.pollXhr=t}}]),n}(x),S=function(e){Object(s.a)(n,e);var t=Object(l.a)(n);function n(e,r){var o;return Object(a.a)(this,n),o=t.call(this),Object(v.a)(Object(u.a)(o),r),o.opts=r,o.method=r.method||"GET",o.uri=e,o.async=!1!==r.async,o.data=void 0!==r.data?r.data:null,o.create(),o}return Object(c.a)(n,[{key:"create",value:function(){var e=this,t=Object(v.b)(this.opts,"agent","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","autoUnref");t.xdomain=!!this.opts.xd,t.xscheme=!!this.opts.xs;var r=this.xhr=new h(t);try{r.open(this.method,this.uri,this.async);try{if(this.opts.extraHeaders)for(var o in r.setDisableHeaderCheck&&r.setDisableHeaderCheck(!0),this.opts.extraHeaders)this.opts.extraHeaders.hasOwnProperty(o)&&r.setRequestHeader(o,this.opts.extraHeaders[o])}catch(i){}if("POST"===this.method)try{r.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(i){}try{r.setRequestHeader("Accept","*/*")}catch(i){}"withCredentials"in r&&(r.withCredentials=this.opts.withCredentials),this.opts.requestTimeout&&(r.timeout=this.opts.requestTimeout),r.onreadystatechange=function(){4===r.readyState&&(200===r.status||1223===r.status?e.onLoad():e.setTimeoutFn((function(){e.onError("number"===typeof r.status?r.status:0)}),0))},r.send(this.data)}catch(i){return void this.setTimeoutFn((function(){e.onError(i)}),0)}"undefined"!==typeof document&&(this.index=n.requestsCount++,n.requests[this.index]=this)}},{key:"onSuccess",value:function(){this.emit("success"),this.cleanup()}},{key:"onData",value:function(e){this.emit("data",e),this.onSuccess()}},{key:"onError",value:function(e){this.emit("error",e),this.cleanup(!0)}},{key:"cleanup",value:function(e){if("undefined"!==typeof this.xhr&&null!==this.xhr){if(this.xhr.onreadystatechange=E,e)try{this.xhr.abort()}catch(t){}"undefined"!==typeof document&&delete n.requests[this.index],this.xhr=null}}},{key:"onLoad",value:function(){var e=this.xhr.responseText;null!==e&&this.onData(e)}},{key:"abort",value:function(){this.cleanup()}}]),n}(m.Emitter);if(S.requestsCount=0,S.requests={},"undefined"!==typeof document)if("function"===typeof attachEvent)attachEvent("onunload",P);else if("function"===typeof addEventListener){var C="onpagehide"in p.a?"pagehide":"unload";addEventListener(C,P,!1)}function P(){for(var e in S.requests)S.requests.hasOwnProperty(e)&&S.requests[e].abort()}var M={websocket:n(280).a,polling:k},T=function(e){Object(s.a)(n,e);var t=Object(l.a)(n);function n(e){var r,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Object(a.a)(this,n),r=t.call(this),e&&"object"===typeof e&&(o=e,e=null),e?(e=i()(e),o.hostname=e.host,o.secure="https"===e.protocol||"wss"===e.protocol,o.port=e.port,e.query&&(o.query=e.query)):o.host&&(o.hostname=i()(o.host).host),Object(v.a)(Object(u.a)(r),o),r.secure=null!=o.secure?o.secure:"undefined"!==typeof location&&"https:"===location.protocol,o.hostname&&!o.port&&(o.port=r.secure?"443":"80"),r.hostname=o.hostname||("undefined"!==typeof location?location.hostname:"localhost"),r.port=o.port||("undefined"!==typeof location&&location.port?location.port:r.secure?"443":"80"),r.transports=o.transports||["polling","websocket"],r.readyState="",r.writeBuffer=[],r.prevBufferLen=0,r.opts=Object.assign({path:"/engine.io",agent:!1,withCredentials:!1,upgrade:!0,timestampParam:"t",rememberUpgrade:!1,rejectUnauthorized:!0,perMessageDeflate:{threshold:1024},transportOptions:{},closeOnBeforeunload:!0},o),r.opts.path=r.opts.path.replace(/\/$/,"")+"/","string"===typeof r.opts.query&&(r.opts.query=O.a.decode(r.opts.query)),r.id=null,r.upgrades=null,r.pingInterval=null,r.pingTimeout=null,r.pingTimeoutTimer=null,"function"===typeof addEventListener&&(r.opts.closeOnBeforeunload&&addEventListener("beforeunload",(function(){r.transport&&(r.transport.removeAllListeners(),r.transport.close())}),!1),"localhost"!==r.hostname&&(r.offlineEventListener=function(){r.onClose("transport close")},addEventListener("offline",r.offlineEventListener,!1))),r.open(),r}return Object(c.a)(n,[{key:"createTransport",value:function(e){var t=function(e){var t={};for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}(this.opts.query);t.EIO=j.e,t.transport=e,this.id&&(t.sid=this.id);var n=Object.assign({},this.opts.transportOptions[e],this.opts,{query:t,socket:this,hostname:this.hostname,secure:this.secure,port:this.port});return new M[e](n)}},{key:"open",value:function(){var e,t=this;if(this.opts.rememberUpgrade&&n.priorWebsocketSuccess&&-1!==this.transports.indexOf("websocket"))e="websocket";else{if(0===this.transports.length)return void this.setTimeoutFn((function(){t.emitReserved("error","No transports available")}),0);e=this.transports[0]}this.readyState="opening";try{e=this.createTransport(e)}catch(r){return this.transports.shift(),void this.open()}e.open(),this.setTransport(e)}},{key:"setTransport",value:function(e){var t=this;this.transport&&this.transport.removeAllListeners(),this.transport=e,e.on("drain",this.onDrain.bind(this)).on("packet",this.onPacket.bind(this)).on("error",this.onError.bind(this)).on("close",(function(){t.onClose("transport close")}))}},{key:"probe",value:function(e){var t=this,r=this.createTransport(e),o=!1;n.priorWebsocketSuccess=!1;var i=function(){o||(r.send([{type:"ping",data:"probe"}]),r.once("packet",(function(e){if(!o)if("pong"===e.type&&"probe"===e.data){if(t.upgrading=!0,t.emitReserved("upgrading",r),!r)return;n.priorWebsocketSuccess="websocket"===r.name,t.transport.pause((function(){o||"closed"!==t.readyState&&(f(),t.setTransport(r),r.send([{type:"upgrade"}]),t.emitReserved("upgrade",r),r=null,t.upgrading=!1,t.flush())}))}else{var i=new Error("probe error");i.transport=r.name,t.emitReserved("upgradeError",i)}})))};function a(){o||(o=!0,f(),r.close(),r=null)}var c=function(e){var n=new Error("probe error: "+e);n.transport=r.name,a(),t.emitReserved("upgradeError",n)};function u(){c("transport closed")}function s(){c("socket closed")}function l(e){r&&e.name!==r.name&&a()}var f=function(){r.removeListener("open",i),r.removeListener("error",c),r.removeListener("close",u),t.off("close",s),t.off("upgrading",l)};r.once("open",i),r.once("error",c),r.once("close",u),this.once("close",s),this.once("upgrading",l),r.open()}},{key:"onOpen",value:function(){if(this.readyState="open",n.priorWebsocketSuccess="websocket"===this.transport.name,this.emitReserved("open"),this.flush(),"open"===this.readyState&&this.opts.upgrade&&this.transport.pause)for(var e=0,t=this.upgrades.length;e0;case $.ACK:case $.BINARY_ACK:return Array.isArray(t)}}}]),n}(m.Emitter);var K=function(){function e(t){Object(a.a)(this,e),this.packet=t,this.buffers=[],this.reconPack=t}return Object(c.a)(e,[{key:"takeBinaryData",value:function(e){if(this.buffers.push(e),this.buffers.length===this.reconPack.attachments){var t=H(this.reconPack,this.buffers);return this.finishedReconstruction(),t}return null}},{key:"finishedReconstruction",value:function(){this.reconPack=null,this.buffers=[]}}]),e}();function G(e,t,n){return e.on(t,n),function(){e.off(t,n)}}var Q=Object.freeze({connect:1,connect_error:1,disconnect:1,disconnecting:1,newListener:1,removeListener:1}),Z=function(e){Object(s.a)(n,e);var t=Object(l.a)(n);function n(e,r,o){var i;return Object(a.a)(this,n),(i=t.call(this)).connected=!1,i.disconnected=!0,i.receiveBuffer=[],i.sendBuffer=[],i.ids=0,i.acks={},i.flags={},i.io=e,i.nsp=r,o&&o.auth&&(i.auth=o.auth),i.io._autoConnect&&i.open(),i}return Object(c.a)(n,[{key:"subEvents",value:function(){if(!this.subs){var e=this.io;this.subs=[G(e,"open",this.onopen.bind(this)),G(e,"packet",this.onpacket.bind(this)),G(e,"error",this.onerror.bind(this)),G(e,"close",this.onclose.bind(this))]}}},{key:"active",get:function(){return!!this.subs}},{key:"connect",value:function(){return this.connected||(this.subEvents(),this.io._reconnecting||this.io.open(),"open"===this.io._readyState&&this.onopen()),this}},{key:"open",value:function(){return this.connect()}},{key:"send",value:function(){for(var e=arguments.length,t=new Array(e),n=0;n1?t-1:0),r=1;r=this._reconnectionAttempts)this.backoff.reset(),this.emitReserved("reconnect_failed"),this._reconnecting=!1;else{var n=this.backoff.duration();this._reconnecting=!0;var r=this.setTimeoutFn((function(){t.skipReconnect||(e.emitReserved("reconnect_attempt",t.backoff.attempts),t.skipReconnect||t.open((function(n){n?(t._reconnecting=!1,t.reconnect(),e.emitReserved("reconnect_error",n)):t.onreconnect()})))}),n);this.opts.autoUnref&&r.unref(),this.subs.push((function(){clearTimeout(r)}))}}},{key:"onreconnect",value:function(){var e=this.backoff.attempts;this._reconnecting=!1,this.backoff.reset(),this.emitReserved("reconnect",e)}}]),n}(m.Emitter),ne={};function re(e,t){"object"===typeof e&&(t=e,e=void 0);var n,r=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2?arguments[2]:void 0,r=e;n=n||"undefined"!==typeof location&&location,null==e&&(e=n.protocol+"//"+n.host),"string"===typeof e&&("/"===e.charAt(0)&&(e="/"===e.charAt(1)?n.protocol+e:n.host+e),/^(https?|wss?):\/\//.test(e)||(e="undefined"!==typeof n?n.protocol+"//"+e:"https://"+e),r=i()(e)),r.port||(/^(http|ws)$/.test(r.protocol)?r.port="80":/^(http|ws)s$/.test(r.protocol)&&(r.port="443")),r.path=r.path||"/";var o=-1!==r.host.indexOf(":")?"["+r.host+"]":r.host;return r.id=r.protocol+"://"+o+":"+r.port+t,r.href=r.protocol+"://"+o+(n&&n.port===r.port?"":":"+r.port),r}(e,(t=t||{}).path||"/socket.io"),o=r.source,a=r.id,c=r.path,u=ne[a]&&c in ne[a].nsps;return t.forceNew||t["force new connection"]||!1===t.multiplex||u?n=new te(o,t):(ne[a]||(ne[a]=new te(o,t)),n=ne[a]),r.query&&!t.query&&(t.query=r.queryKey),n.socket(r.path,t)}Object.assign(re,{Manager:te,Socket:Z,io:re,connect:re})},function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));var r=n(19);function o(e){return Object(r.a)(1,arguments),e instanceof Date||"object"===typeof e&&"[object Date]"===Object.prototype.toString.call(e)}var i=n(26);function a(e){if(Object(r.a)(1,arguments),!o(e)&&"number"!==typeof e)return!1;var t=Object(i.a)(e);return!isNaN(Number(t))}},function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var r=n(153);function o(e){if("string"!==typeof e)throw new Error(Object(r.a)(7));return e.charAt(0).toUpperCase()+e.slice(1)}},function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));var r=n(0),o=n(120);function i(e,t){return r.useMemo((function(){return null==e&&null==t?null:function(n){Object(o.a)(e,n),Object(o.a)(t,n)}}),[e,t])}},function(e,t,n){"use strict";var r=n(2),o=n(4),i=n(0),a=n(6),c=n(155),u=n(8),s=n(10),l=n(5),f=n(84),d=n(104);function p(e){return Object(f.a)("MuiSvgIcon",e)}Object(d.a)("MuiSvgIcon",["root","colorPrimary","colorSecondary","colorAction","colorError","colorDisabled","fontSizeInherit","fontSizeSmall","fontSizeMedium","fontSizeLarge"]);var h=n(1),v=["children","className","color","component","fontSize","htmlColor","titleAccess","viewBox"],m=Object(l.a)("svg",{name:"MuiSvgIcon",slot:"Root",overridesResolver:function(e,t){var n=e.ownerState;return[t.root,"inherit"!==n.color&&t["color".concat(Object(u.a)(n.color))],t["fontSize".concat(Object(u.a)(n.fontSize))]]}})((function(e){var t,n,r=e.theme,o=e.ownerState;return{userSelect:"none",width:"1em",height:"1em",display:"inline-block",fill:"currentColor",flexShrink:0,transition:r.transitions.create("fill",{duration:r.transitions.duration.shorter}),fontSize:{inherit:"inherit",small:r.typography.pxToRem(20),medium:r.typography.pxToRem(24),large:r.typography.pxToRem(35)}[o.fontSize],color:null!=(t=null==(n=r.palette[o.color])?void 0:n.main)?t:{action:r.palette.action.active,disabled:r.palette.action.disabled,inherit:void 0}[o.color]}})),g=i.forwardRef((function(e,t){var n=Object(s.a)({props:e,name:"MuiSvgIcon"}),i=n.children,l=n.className,f=n.color,d=void 0===f?"inherit":f,g=n.component,b=void 0===g?"svg":g,y=n.fontSize,w=void 0===y?"medium":y,O=n.htmlColor,j=n.titleAccess,x=n.viewBox,E=void 0===x?"0 0 24 24":x,_=Object(o.a)(n,v),k=Object(r.a)({},n,{color:d,component:b,fontSize:w,viewBox:E}),S=function(e){var t=e.color,n=e.fontSize,r=e.classes,o={root:["root","inherit"!==t&&"color".concat(Object(u.a)(t)),"fontSize".concat(Object(u.a)(n))]};return Object(c.a)(o,p,r)}(k);return Object(h.jsxs)(m,Object(r.a)({as:b,className:Object(a.a)(S.root,l),ownerState:k,focusable:"false",viewBox:E,color:O,"aria-hidden":!j||void 0,role:j?"img":void 0,ref:t},_,{children:[i,j?Object(h.jsx)("title",{children:j}):null]}))}));g.muiName="SvgIcon";t.a=g},,,,,,,,,,,,,,function(e,t,n){"use strict";var r=n(159),o=60103,i=60106;t.Fragment=60107,t.StrictMode=60108,t.Profiler=60114;var a=60109,c=60110,u=60112;t.Suspense=60113;var s=60115,l=60116;if("function"===typeof Symbol&&Symbol.for){var f=Symbol.for;o=f("react.element"),i=f("react.portal"),t.Fragment=f("react.fragment"),t.StrictMode=f("react.strict_mode"),t.Profiler=f("react.profiler"),a=f("react.provider"),c=f("react.context"),u=f("react.forward_ref"),t.Suspense=f("react.suspense"),s=f("react.memo"),l=f("react.lazy")}var d="function"===typeof Symbol&&Symbol.iterator;function p(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n